dashboard.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. pub mod pane;
  2. pub use pane::{Uuid, PaneState, PaneContent, PaneSettings};
  3. use crate::{
  4. charts::{candlestick::CandlestickChart, footprint::FootprintChart, Message},
  5. data_providers::{
  6. Depth, Exchange, Kline, TickMultiplier, Ticker, Timeframe, Trade
  7. },
  8. StreamType
  9. };
  10. use std::{collections::{HashMap, HashSet}, rc::Rc};
  11. use iced::widget::pane_grid::{self, Configuration};
  12. pub struct Dashboard {
  13. pub panes: pane_grid::State<PaneState>,
  14. pub show_layout_modal: bool,
  15. pub focus: Option<pane_grid::Pane>,
  16. pub first_pane: pane_grid::Pane,
  17. pub pane_lock: bool,
  18. pub pane_state_cache: HashMap<Uuid, (Option<Ticker>, Option<Timeframe>, Option<f32>)>,
  19. pub last_axis_split: Option<pane_grid::Axis>,
  20. }
  21. impl Dashboard {
  22. pub fn empty(pane_config: Configuration<PaneState>) -> Self {
  23. let panes: pane_grid::State<PaneState> = pane_grid::State::with_configuration(pane_config);
  24. let first_pane: pane_grid::Pane = *panes.panes.iter().next().unwrap().0;
  25. Self {
  26. show_layout_modal: false,
  27. panes,
  28. focus: None,
  29. first_pane,
  30. pane_lock: false,
  31. pane_state_cache: HashMap::new(),
  32. last_axis_split: None,
  33. }
  34. }
  35. pub fn update_chart_state(&mut self, pane_id: Uuid, message: Message) -> Result<(), &str> {
  36. for (_, pane_state) in self.panes.iter_mut() {
  37. if pane_state.id == pane_id {
  38. match pane_state.content {
  39. PaneContent::Heatmap(ref mut chart) => {
  40. chart.update(&message);
  41. return Ok(());
  42. },
  43. PaneContent::Footprint(ref mut chart) => {
  44. chart.update(&message);
  45. return Ok(());
  46. },
  47. PaneContent::Candlestick(ref mut chart) => {
  48. chart.update(&message);
  49. return Ok(());
  50. },
  51. _ => {
  52. return Err("No chart found");
  53. }
  54. }
  55. }
  56. }
  57. Err("No pane found")
  58. }
  59. pub fn get_pane_stream_mut(&mut self, pane_id: Uuid) -> Result<&mut Vec<StreamType>, &str> {
  60. for (_, pane_state) in self.panes.iter_mut() {
  61. if pane_state.id == pane_id {
  62. return Ok(&mut pane_state.stream);
  63. }
  64. }
  65. Err("No pane found")
  66. }
  67. pub fn get_pane_settings_mut(&mut self, pane_id: Uuid) -> Result<&mut PaneSettings, &str> {
  68. for (_, pane_state) in self.panes.iter_mut() {
  69. if pane_state.id == pane_id {
  70. return Ok(&mut pane_state.settings);
  71. }
  72. }
  73. Err("No pane found")
  74. }
  75. pub fn set_pane_content(&mut self, pane_id: Uuid, content: PaneContent) -> Result<(), &str> {
  76. for (_, pane_state) in self.panes.iter_mut() {
  77. if pane_state.id == pane_id {
  78. pane_state.content = content;
  79. return Ok(());
  80. }
  81. }
  82. Err("No pane found")
  83. }
  84. pub fn pane_change_ticksize(&mut self, pane_id: Uuid, new_tick_multiply: TickMultiplier) -> Result<(), &str> {
  85. for (_, pane_state) in self.panes.iter_mut() {
  86. if pane_state.id == pane_id {
  87. pane_state.settings.tick_multiply = Some(new_tick_multiply);
  88. if let Some(min_tick_size) = pane_state.settings.min_tick_size {
  89. match pane_state.content {
  90. PaneContent::Footprint(ref mut chart) => {
  91. chart.change_tick_size(
  92. new_tick_multiply.multiply_with_min_tick_size(min_tick_size)
  93. );
  94. return Ok(());
  95. },
  96. _ => {
  97. return Err("No footprint chart found");
  98. }
  99. }
  100. } else {
  101. return Err("No min tick size found");
  102. }
  103. }
  104. }
  105. Err("No pane found")
  106. }
  107. pub fn pane_change_timeframe(&mut self, pane_id: Uuid, new_timeframe: Timeframe) -> Result<&StreamType, &str> {
  108. for (_, pane_state) in self.panes.iter_mut() {
  109. if pane_state.id == pane_id {
  110. pane_state.settings.selected_timeframe = Some(new_timeframe);
  111. for stream_type in pane_state.stream.iter_mut() {
  112. match stream_type {
  113. StreamType::Kline { timeframe, .. } => {
  114. *timeframe = new_timeframe;
  115. match pane_state.content {
  116. PaneContent::Candlestick(_) => {
  117. return Ok(stream_type);
  118. },
  119. PaneContent::Footprint(_) => {
  120. return Ok(stream_type);
  121. },
  122. _ => {}
  123. }
  124. },
  125. _ => {}
  126. }
  127. }
  128. }
  129. }
  130. Err("No pane found")
  131. }
  132. pub fn pane_set_size_filter(&mut self, pane_id: Uuid, new_size_filter: f32) -> Result<(), &str> {
  133. for (_, pane_state) in self.panes.iter_mut() {
  134. if pane_state.id == pane_id {
  135. match pane_state.content {
  136. PaneContent::Heatmap(ref mut chart) => {
  137. chart.set_size_filter(new_size_filter);
  138. return Ok(());
  139. },
  140. PaneContent::TimeAndSales(ref mut chart) => {
  141. chart.set_size_filter(new_size_filter);
  142. return Ok(());
  143. },
  144. _ => {
  145. return Err("No footprint chart found");
  146. }
  147. }
  148. }
  149. }
  150. Err("No pane found")
  151. }
  152. pub fn insert_klines_vec(&mut self, stream_type: &StreamType, klines: &Vec<Kline>, pane_id: Uuid) {
  153. for (_, pane_state) in self.panes.iter_mut() {
  154. if pane_state.id == pane_id {
  155. match stream_type {
  156. StreamType::Kline { timeframe, .. } => {
  157. let timeframe_u16 = timeframe.to_minutes();
  158. match &mut pane_state.content {
  159. PaneContent::Candlestick(chart) => {
  160. *chart = CandlestickChart::new(klines.to_vec(), timeframe_u16);
  161. },
  162. PaneContent::Footprint(chart) => {
  163. let raw_trades = chart.get_raw_trades();
  164. let tick_size = chart.get_tick_size();
  165. *chart = FootprintChart::new(timeframe_u16, tick_size, klines.to_vec(), raw_trades);
  166. },
  167. _ => {}
  168. }
  169. },
  170. _ => {}
  171. }
  172. }
  173. }
  174. }
  175. pub fn update_latest_klines(&mut self, stream_type: &StreamType, kline: &Kline) -> Result<(), &str> {
  176. let mut found_match = false;
  177. for (_, pane_state) in self.panes.iter_mut() {
  178. if pane_state.matches_stream(&stream_type) {
  179. match &mut pane_state.content {
  180. PaneContent::Candlestick(chart) => chart.update_latest_kline(kline),
  181. PaneContent::Footprint(chart) => chart.update_latest_kline(kline),
  182. _ => {}
  183. }
  184. found_match = true;
  185. }
  186. }
  187. if found_match {
  188. Ok(())
  189. } else {
  190. Err("No matching pane found for the stream")
  191. }
  192. }
  193. pub fn update_depth_and_trades(&mut self, stream_type: StreamType, depth_update_t: i64, depth: Depth, trades_buffer: Vec<Trade>) -> Result<(), &str> {
  194. let mut found_match = false;
  195. let depth = Rc::new(depth);
  196. let trades_buffer = trades_buffer.into_boxed_slice();
  197. for (_, pane_state) in self.panes.iter_mut() {
  198. if pane_state.matches_stream(&stream_type) {
  199. match &mut pane_state.content {
  200. PaneContent::Heatmap(chart) => {
  201. chart.insert_datapoint(&trades_buffer, depth_update_t, Rc::clone(&depth));
  202. },
  203. PaneContent::Footprint(chart) => {
  204. chart.insert_datapoint(&trades_buffer, depth_update_t);
  205. },
  206. PaneContent::TimeAndSales(chart) => {
  207. chart.update(&trades_buffer);
  208. },
  209. _ => {}
  210. }
  211. found_match = true;
  212. }
  213. }
  214. if found_match {
  215. Ok(())
  216. } else {
  217. Err("No matching pane found for the stream")
  218. }
  219. }
  220. pub fn get_all_diff_streams(&self) -> HashMap<Exchange, HashMap<Ticker, HashSet<StreamType>>> {
  221. let mut pane_streams = HashMap::new();
  222. for (_, pane_state) in self.panes.iter() {
  223. for stream_type in &pane_state.stream {
  224. match stream_type {
  225. StreamType::Kline { exchange, ticker, timeframe } => {
  226. let exchange = exchange.clone();
  227. let ticker = ticker.clone();
  228. let timeframe = timeframe.clone();
  229. let exchange_map = pane_streams.entry(exchange.clone()).or_insert(HashMap::new());
  230. let ticker_map = exchange_map.entry(ticker).or_insert(HashSet::new());
  231. ticker_map.insert(StreamType::Kline { exchange, ticker, timeframe });
  232. },
  233. StreamType::DepthAndTrades { exchange, ticker } => {
  234. let exchange = exchange.clone();
  235. let ticker = ticker.clone();
  236. let exchange_map = pane_streams.entry(exchange).or_insert(HashMap::new());
  237. let ticker_map = exchange_map.entry(ticker).or_insert(HashSet::new());
  238. ticker_map.insert(StreamType::DepthAndTrades { exchange, ticker });
  239. },
  240. _ => {}
  241. }
  242. }
  243. }
  244. pane_streams
  245. }
  246. }