Explorar o código

add experimental depth heatmaps

Berke hai 1 ano
pai
achega
9453c93225
Modificáronse 1 ficheiros con 44 adicións e 24 borrados
  1. 44 24
      src/main.rs

+ 44 - 24
src/main.rs

@@ -155,10 +155,9 @@ impl Application for State {
                     self.ws_state = WsState::Disconnected;
                     Command::none()
                 }
-                ws_binance::Event::DepthReceived(depth_update, bids, _asks, trades_buffer) => {
-                    let best_bid_price = bids.first().map(|(price, _)| *price).unwrap_or(0.0);
+                ws_binance::Event::DepthReceived(depth_update, bids, asks, trades_buffer) => {
                     if let Some(chart) = &mut self.trades_chart {
-                        chart.update(depth_update, trades_buffer, best_bid_price);
+                        chart.update(depth_update, trades_buffer, bids, asks);
                     }
                     Command::none()
                 }
@@ -338,19 +337,19 @@ impl Chart<Message> for CandlestickChart {
 struct LineChart {
     cache: Cache,
     data_points: VecDeque<(DateTime<Utc>, f32, f32, bool)>,
-    bid_prices: VecDeque<(DateTime<Utc>, f32)>,
+    depth: VecDeque<(DateTime<Utc>, Vec<(f32, f32)>, Vec<(f32, f32)>)>,
 }
 impl LineChart {
     fn new() -> Self {
         Self {
             cache: Cache::new(),
             data_points: VecDeque::new(),
-            bid_prices: VecDeque::new(),
+            depth: VecDeque::new(),
         }
     }
 
-    fn update(&mut self, depth_update: u64, mut trades_buffer: Vec<ws_binance::Trade>, best_bid_price: f32) {
-        let aggregate_time = 250; 
+    fn update(&mut self, depth_update: u64, mut trades_buffer: Vec<ws_binance::Trade>, bids: Vec<(f32, f32)>, asks: Vec<(f32, f32)>) {
+        let aggregate_time = 100; 
         let depth_update_time = DateTime::<Utc>::from_utc(
             NaiveDateTime::from_timestamp(
                 (depth_update / 1000) as i64, 
@@ -358,16 +357,22 @@ impl LineChart {
             ), 
             Utc
         );
-        self.bid_prices.push_back((depth_update_time, best_bid_price));
 
         for trade in trades_buffer.drain(..) {
             self.data_points.push_back((depth_update_time, trade.price, trade.qty, trade.is_sell));
         }
+        if let Some((time, _, _)) = self.depth.back() {
+            if *time == depth_update_time {
+                self.depth.pop_back();
+            }
+        }
+        self.depth.push_back((depth_update_time, bids, asks));
+
         while self.data_points.len() > 6000 {
             self.data_points.pop_front();
-            self.bid_prices.pop_front();
+            self.depth.pop_front();
         }
-
+        
         self.cache.clear();
     }
 
@@ -393,8 +398,6 @@ impl Chart<Message> for LineChart {
 
     fn build_chart<DB: DrawingBackend>(&self, _state: &Self::State, mut chart: ChartBuilder<DB>) {
         use plotters::prelude::*;
-
-        const PLOT_LINE_COLOR: RGBColor = RGBColor(0, 175, 255);
         
         if self.data_points.len() > 1 {
             // x-axis range, acquire time range
@@ -418,9 +421,11 @@ impl Chart<Message> for LineChart {
                 }
             }).collect();
 
-            let recent_bid_prices: Vec<_> = self.bid_prices.iter().filter_map(|&(time, price)| {
-                if time >= oldest_time && time <= newest_time {
-                    Some((time, price))
+            let recent_depth: Vec<_> = self.depth.iter().filter_map(|(time, bids, asks)| {
+                if time >= &oldest_time && time <= &newest_time {
+                    y_min = y_min.min(bids.iter().map(|(price, _qty)| *price).fold(f32::MAX, f32::min));
+                    y_max = y_max.max(asks.iter().map(|(price, _qty)| *price).fold(f32::MIN, f32::max));
+                    Some((time, bids, asks))
                 } else {
                     None
                 }
@@ -458,16 +463,31 @@ impl Chart<Message> for LineChart {
                 .draw()
                 .expect("failed to draw chart mesh");
 
-            chart
-                .draw_series(
-                    AreaSeries::new(
-                        recent_bid_prices.iter().map(|&(time, price)| (time, price)),
-                        0_f32,
-                        PLOT_LINE_COLOR.mix(0.175),
+            for i in 0..20 { 
+                let bids_i: Vec<(DateTime<Utc>, f32, f32)> = recent_depth.iter().map(|&(time, bid, _ask)| ((*time).clone(), bid[i].0, bid[i].1)).collect();
+                let asks_i: Vec<(DateTime<Utc>, f32, f32)> = recent_depth.iter().map(|&(time, _bid, ask)| ((*time).clone(), ask[i].0, ask[i].1)).collect();
+            
+                let max_bid_quantity = bids_i.iter().map(|&(_time, _price, quantity)| quantity).fold(f32::MIN, f32::max);
+                let max_ask_quantity = asks_i.iter().map(|&(_time, _price, quantity)| quantity).fold(f32::MIN, f32::max);
+            
+                chart
+                    .draw_series(
+                        bids_i.iter().map(|&(time, price, quantity)| {
+                            let alpha = 0.1 + 0.9 * (quantity / max_bid_quantity);
+                            Pixel::new((time, price), RGBAColor(0, 128, 128, alpha.into()))
+                        }),
                     )
-                    .border_style(ShapeStyle::from(PLOT_LINE_COLOR).stroke_width(2)),
-                )
-                .expect("failed to draw chart data");
+                    .expect(&format!("failed to draw bids_{}", i));
+            
+                chart
+                    .draw_series(
+                        asks_i.iter().map(|&(time, price, quantity)| {
+                            let alpha = 0.1 + 0.9 * (quantity / max_ask_quantity);
+                            Pixel::new((time, price), RGBAColor(128, 0, 128, alpha.into()))
+                        }),
+                    )
+                    .expect(&format!("failed to draw asks_{}", i));
+            }
             
             let qty_min = recent_data_points.iter().map(|&(_, _, qty, _)| qty).fold(f32::MAX, f32::min);
             let qty_max = recent_data_points.iter().map(|&(_, _, qty, _)| qty).fold(f32::MIN, f32::max);