Skip to main content

btrader/
trader.rs

1use crate::calculation_cluster::CalculationCluster;
2use crate::config::Configuration;
3use crate::depth_cache::DepthCache;
4use crate::trading_pair::TradingPair;
5use crate::triangular_relationship::TriangularRelationship;
6use binance::api::*;
7use binance::general::*;
8use binance::model::*;
9use console::style;
10use std::collections::HashMap;
11use std::fmt;
12
13/*
14 *  bTrader
15 */
16#[allow(non_camel_case_types)]
17pub struct bTrader {
18  calculation_cluster: CalculationCluster,
19}
20
21impl fmt::Display for bTrader {
22  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
23    write!(f, "<bTrader>")
24  }
25}
26
27impl bTrader {
28  // Constructor
29  pub fn new(config_path: &str) -> bTrader {
30    // Starting with configuration
31    let config: Configuration = Configuration::new(config_path);
32    // Getting information from Binance...
33    print!("{} Connecting to Binance...", style("[1/7]").bold().dim(),);
34    let general: General = Binance::new(None, None);
35    println!(" Successfully connected!");
36    // Get trading pairs
37    print!("{} Getting trading pairs...", style("[2/7]").bold().dim(),);
38    let mut pairs: Vec<TradingPair> = Vec::new();
39    let result = match general.exchange_info() {
40      Ok(answer) => answer,
41      Err(e) => panic!("Error on getting exchange info: {}", e),
42    };
43    for symbol in &result.symbols {
44      // Checks if symbol is currently trading
45      if symbol.status == "TRADING" {
46        let mut step: f64 = 0.0;
47        // Get step for this symbol
48        for filter in &symbol.filters {
49          if let Filters::LotSize {
50            min_qty: _,
51            max_qty: _,
52            step_size,
53          } = filter
54          {
55            step = step_size.parse().unwrap()
56          };
57        }
58        pairs.push(TradingPair::new(
59          symbol.symbol.to_string(),
60          symbol.base_asset.to_string(),
61          symbol.quote_asset.to_string(),
62          step,
63        ));
64      }
65    }
66    println!(" {} symbols found!", pairs.len());
67    // Get start/end pairs
68    print!(
69      "{} Getting arbitrage deal starters...",
70      style("[3/7]").bold().dim(),
71    );
72    let mut starters: Vec<TradingPair> = Vec::new();
73    for pair in &pairs {
74      if pair.has_asset(config.investment_base.to_string()) {
75        starters.push(pair.clone());
76      }
77    }
78    println!(
79      " {} symbols could start or end a triangular operation.",
80      starters.len()
81    );
82    // Get relationships
83    print!(
84      "{} Computing triangular relationships...",
85      style("[4/7]").bold().dim(),
86    );
87    let mut relationships: HashMap<String, TriangularRelationship> = HashMap::new();
88    let mut socket_pairs: Vec<String> = Vec::new();
89    for (i, start_pair) in starters[0..starters.len() - 1].iter().enumerate() {
90      for end_pair in starters[i + 1..starters.len()].iter() {
91        let middle = TradingPair::new(
92          "".to_string(),
93          start_pair.get_the_other(config.investment_base.to_string()),
94          end_pair.get_the_other(config.investment_base.to_string()),
95          0.0,
96        );
97        for middle_pair in pairs.iter() {
98          if middle_pair == &middle {
99            // Add start pair to sockets list
100            if !socket_pairs.contains(&start_pair.get_symbol()) {
101              socket_pairs.push(start_pair.get_symbol());
102            }
103            // Add middle pair to sockets list
104            if !socket_pairs.contains(&middle_pair.get_symbol()) {
105              socket_pairs.push(middle_pair.get_symbol());
106            }
107            // Add end pair to sockets list
108            if !socket_pairs.contains(&end_pair.get_symbol()) {
109              socket_pairs.push(end_pair.get_symbol());
110            }
111            relationships.insert(
112              format!(
113                "{} -> {} -> {}",
114                start_pair.get_symbol(),
115                middle_pair.get_symbol(),
116                end_pair.get_symbol()
117              ),
118              TriangularRelationship::new(
119                config.investment_base.to_string(),
120                TradingPair::new(
121                  start_pair.get_symbol(),
122                  start_pair.get_base_asset(),
123                  start_pair.get_quote_asset(),
124                  start_pair.get_step(),
125                ),
126                TradingPair::new(
127                  middle_pair.get_symbol(),
128                  middle_pair.get_base_asset(),
129                  middle_pair.get_quote_asset(),
130                  middle_pair.get_step(),
131                ),
132                TradingPair::new(
133                  end_pair.get_symbol(),
134                  end_pair.get_base_asset(),
135                  end_pair.get_quote_asset(),
136                  end_pair.get_step(),
137                ),
138              ),
139            );
140            break;
141          }
142        }
143      }
144    }
145    println!(
146      " {} triangular relationships found, will have to handle {} websockets",
147      relationships.len(),
148      socket_pairs.len()
149    );
150    let depth_cache = DepthCache::new(&socket_pairs, 8, 1);
151    let calculation_cluster = CalculationCluster::new(relationships, depth_cache, config);
152    bTrader {
153      calculation_cluster,
154    }
155  }
156  // Execute
157  pub fn run(&self) {
158    self.calculation_cluster.start();
159  }
160}