use kucoin_arbitrage::broker::gatekeeper::kucoin::task_gatekeep_chances;
use kucoin_arbitrage::broker::order::kucoin::task_place_order;
use kucoin_arbitrage::broker::orderbook::kucoin::{task_pub_orderbook_event, task_sync_orderbook};
use kucoin_arbitrage::broker::symbol::filter::{symbol_with_quotes, vector_to_hash};
use kucoin_arbitrage::broker::symbol::kucoin::get_symbols;
use kucoin_arbitrage::event::chance::ChanceEvent;
use kucoin_arbitrage::event::order::OrderEvent;
use kucoin_arbitrage::event::orderbook::OrderbookEvent;
use kucoin_arbitrage::model::orderbook::FullOrderbook;
use kucoin_arbitrage::strategy::all_taker_btc_usd::task_pub_chance_all_taker_btc_usd;
use kucoin_arbitrage::translator::translator::OrderBookTranslator;
use kucoin_api::{
client::{Kucoin, KucoinEnv},
model::market::OrderBookType,
model::websocket::{WSTopic, WSType},
};
use std::sync::{Arc, Mutex};
use tokio::sync::broadcast::channel;
fn prune_vector<T>(input_vec: Vec<T>, n: usize) -> Vec<T> {
let mut output_vec = Vec::new();
for (index, value) in input_vec.into_iter().enumerate() {
if index >= n {
break;
}
output_vec.push(value);
}
output_vec
}
#[tokio::main]
async fn main() -> Result<(), kucoin_api::failure::Error> {
kucoin_arbitrage::logger::log_init();
log::info!("Log setup");
let credentials = kucoin_arbitrage::globals::config::credentials();
let api = Kucoin::new(KucoinEnv::Live, Some(credentials))?;
let url = api.clone().get_socket_endpoint(WSType::Public).await?;
log::info!("Credentials setup");
let symbol_list = get_symbols(api.clone()).await;
let symbol_infos = symbol_with_quotes(&symbol_list, "BTC", "USDT");
let hash_symbols = Arc::new(Mutex::new(vector_to_hash(&symbol_infos)));
let symbol_infos = prune_vector(symbol_infos, 99);
let mut symbols = Vec::new();
for symbol_info in symbol_infos {
symbols.push(symbol_info.symbol);
}
log::info!("{symbols:#?}");
let mut ws = api.websocket();
let subs = vec![WSTopic::OrderBook(symbols.to_vec())];
ws.subscribe(url, subs).await?;
log::info!("Websocket subscription setup");
let (tx_orderbook, rx_orderbook) = channel::<OrderbookEvent>(1024 * 2);
let (tx_orderbook_best, rx_orderbook_best) = channel::<OrderbookEvent>(1024);
let (tx_chance, rx_chance) = channel::<ChanceEvent>(64);
let (tx_order, rx_order) = channel::<OrderEvent>(16);
log::info!("broadcast channels setup");
let full_orderbook = Arc::new(Mutex::new(FullOrderbook::new()));
log::info!("Local Orderbook setup");
tokio::spawn(task_sync_orderbook(
rx_orderbook,
tx_orderbook_best,
full_orderbook.clone(),
));
tokio::spawn(task_pub_chance_all_taker_btc_usd(
rx_orderbook_best,
tx_chance,
full_orderbook.clone(),
hash_symbols,
));
tokio::spawn(task_gatekeep_chances(rx_chance, tx_order));
tokio::spawn(task_place_order(rx_order, api.clone()));
let full_orderbook_2 = full_orderbook.clone();
for symbol in symbols.iter() {
log::info!("obtaining initial orderbook[{symbol}] from REST");
let res = api
.clone()
.get_orderbook(symbol.as_str(), OrderBookType::L100)
.await
.expect("invalid data");
if let Some(data) = res.data {
log::info!("Initial sequence {}:{}", symbol, data.sequence);
let mut x = full_orderbook_2.lock().unwrap();
(*x).insert(symbol.to_string(), data.to_internal());
} else {
log::warn!("orderbook[{symbol}] received none")
}
}
tokio::spawn(task_pub_orderbook_event(ws, tx_orderbook));
log::info!("task_pub_orderevent setup");
log::info!("all application tasks setup");
let _res = tokio::join!(kucoin_arbitrage::tasks::background_routine());
panic!("Program should not arrive here")
}