|
|
@@ -12,11 +12,12 @@ use tokio::time::sleep;
|
|
|
use tracing::{error, info};
|
|
|
use exchanges::binance_spot_ws::{BinanceSpotSubscribeType, BinanceSpotWs, BinanceSpotWsType};
|
|
|
use exchanges::binance_swap_ws::{BinanceSubscribeType, BinanceSwapWs, BinanceWsType};
|
|
|
+use exchanges::bitget_spot_ws::{BitgetSpotWs, BitgetSubscribeType};
|
|
|
use exchanges::gate_swap_rest::GateSwapRest;
|
|
|
use exchanges::gate_swap_ws::{GateSubscribeType, GateSwapWs, GateWsType};
|
|
|
use exchanges::kucoin_swap_ws::{KucoinSubscribeType, KucoinSwapWs, KucoinWsType};
|
|
|
use global::trace_stack::TraceStack;
|
|
|
-use standard::exchange::ExchangeEnum::{BinanceSpot, BinanceSwap, GateSwap, KucoinSwap};
|
|
|
+use standard::exchange::ExchangeEnum::{BinanceSpot, BinanceSwap, BitgetSpot, GateSwap, KucoinSwap};
|
|
|
use standard::SpecialTicker;
|
|
|
use crate::model::{OrderInfo, OriginalTicker, OriginalTradeBa, OriginalTradeGa};
|
|
|
use crate::quant::Quant;
|
|
|
@@ -29,6 +30,9 @@ pub async fn run_transactional_exchange(bool_v1 :Arc<AtomicBool>, exchange_name:
|
|
|
}
|
|
|
"kucoin_usdt_swap" => {
|
|
|
kucoin_swap_run(bool_v1, 1i8, quant_arc, name, symbols, exchange_params).await;
|
|
|
+ },
|
|
|
+ "bitget_usdt_spot" => {
|
|
|
+ bitget_spot_run(bool_v1,1i8, quant_arc, name, symbols, exchange_params).await;
|
|
|
}
|
|
|
_ => {
|
|
|
error!("交易交易所启动失败,参数错误!")
|
|
|
@@ -50,6 +54,9 @@ pub async fn run_reference_exchange(bool_v1 :Arc<AtomicBool>, exchange_name: Str
|
|
|
}
|
|
|
"kucoin_usdt_swap" => {
|
|
|
kucoin_swap_run(bool_v1,0i8, quant_arc, name, symbols, exchange_params).await;
|
|
|
+ },
|
|
|
+ "bitget_usdt_spot" => {
|
|
|
+ bitget_spot_run(bool_v1,0i8, quant_arc, name, symbols, exchange_params).await;
|
|
|
}
|
|
|
_ => {
|
|
|
error!("参考交易所启动失败,参数错误!")
|
|
|
@@ -61,13 +68,17 @@ pub async fn run_reference_exchange(bool_v1 :Arc<AtomicBool>, exchange_name: Str
|
|
|
async fn gate_swap_run(bool_v1 :Arc<AtomicBool>, type_num: i8, quant_arc: Arc<Mutex<Quant>>, name: String, symbols: Vec<String>, exchange_params: BTreeMap<String, String>){
|
|
|
let (tx, mut rx) = channel(100);
|
|
|
let mut gate_exc = GateSwapRest::new(false, exchange_params.clone());
|
|
|
- // 获取user_id
|
|
|
- let res_data = gate_exc.wallet_fee().await;
|
|
|
- assert_eq!(res_data.code, "200", "获取gate交易所参数 user_id 失败, 启动失败!");
|
|
|
+ let user_id;
|
|
|
+ if type_num == 1{
|
|
|
+ // 获取user_id
|
|
|
+ let res_data = gate_exc.wallet_fee().await;
|
|
|
+ assert_eq!(res_data.code, "200", "获取gate交易所参数 user_id 失败, 启动失败!");
|
|
|
+
|
|
|
+ let wallet_obj :Value = serde_json::from_str(&res_data.data).unwrap();
|
|
|
+ info!(?wallet_obj);
|
|
|
+ user_id = wallet_obj["user_id"].to_string();
|
|
|
+ }
|
|
|
|
|
|
- let wallet_obj :Value = serde_json::from_str(&res_data.data).unwrap();
|
|
|
- info!(?wallet_obj);
|
|
|
- let user_id = wallet_obj["user_id"].to_string();
|
|
|
let symbols_one = symbols.clone();
|
|
|
// 获取乘数(计价货币兑换为结算货币的乘数)
|
|
|
let response = gate_exc.get_market_details("usdt".to_string()).await;
|
|
|
@@ -208,7 +219,7 @@ async fn kucoin_swap_run(bool_v1 :Arc<AtomicBool>, type_num: i8, quant_arc: Arc<
|
|
|
let symbols_clone = symbols.clone();
|
|
|
let mut symbol_arr = Vec::new();
|
|
|
for symbol in symbols_clone{
|
|
|
- let new_symbol = symbol.replace("_", "").to_uppercase() + "M";
|
|
|
+ let new_symbol = symbol.replace("_", "").to_uppercase() + "M";
|
|
|
symbol_arr.push(new_symbol);
|
|
|
}
|
|
|
spawn( async move {
|
|
|
@@ -535,6 +546,123 @@ async fn reference_binance_swap_run(bool_v1 :Arc<AtomicBool>, quant_arc: Arc<Mut
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+async fn bitget_spot_run(bool_v1 :Arc<AtomicBool>, type_num: i8, quant_arc: Arc<Mutex<Quant>>, name: String, symbols: Vec<String>, exchange_params: BTreeMap<String, String>) {
|
|
|
+ let (tx, mut rx) = channel(100);
|
|
|
+ spawn( async move {
|
|
|
+ let mut bit_exc = BitgetSpotWs::new_label(name, false, exchange_params, BitgetSpot::PublicAndPrivate, tx);
|
|
|
+ // 交易
|
|
|
+ if type_num == 1 {
|
|
|
+ bit_exc.set_subscribe(vec![
|
|
|
+ BitgetSubscribeType::PuTrade,
|
|
|
+ BitgetSubscribeType::PuBooks5,
|
|
|
+ BitgetSubscribeType::PrAccount,
|
|
|
+ BitgetSubscribeType::PrOrders
|
|
|
+ ]);
|
|
|
+ } else { // 参考
|
|
|
+ bit_exc.set_subscribe(vec![
|
|
|
+ BitgetSubscribeType::PuTrade,
|
|
|
+ BitgetSubscribeType::PuBooks5
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ bit_exc.custom_subscribe(bool_v1, symbols.clone()).await;
|
|
|
+ });
|
|
|
+ spawn(async move {
|
|
|
+ let bot_arc_clone = Arc::clone(&quant_arc);
|
|
|
+ let multiplier = bot_arc_clone.lock().await.platform_rest.get_self_market().amount_size;
|
|
|
+ // trade
|
|
|
+ let mut max_buy = Decimal::ZERO;
|
|
|
+ let mut min_sell = Decimal::ZERO;
|
|
|
+ let run_symbol = symbols.clone()[0].clone();
|
|
|
+
|
|
|
+ loop {
|
|
|
+ sleep(Duration::from_millis(1)).await;
|
|
|
+ let mut trace_stack = TraceStack::default();
|
|
|
+
|
|
|
+ match rx.recv().await {
|
|
|
+ Some(data) => {
|
|
|
+ trace_stack.on_network(data.time);
|
|
|
+ trace_stack.on_before_quant();
|
|
|
+
|
|
|
+ if data.code != "200".to_string() {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if data.channel == "books5" {
|
|
|
+ trace_stack.on_before_format();
|
|
|
+ let depth = standard::handle_info::HandleSwapInfo::handle_special_depth(BitgetSpot, data);
|
|
|
+ trace_stack.on_after_format();
|
|
|
+ {
|
|
|
+ let mut quant = bot_arc_clone.lock().await;
|
|
|
+ quant._update_ticker(depth.ticker.clone(), depth.name.clone());
|
|
|
+ quant._update_depth(depth.depth.clone(), depth.name.clone(), &mut trace_stack);
|
|
|
+ quant.local_depths.insert(depth.name, depth.depth);
|
|
|
+ }
|
|
|
+ } else if data.channel == "trade" {
|
|
|
+ let mut quant = bot_arc_clone.lock().await;
|
|
|
+ let str = data.label.clone();
|
|
|
+ if quant.is_update.contains_key(&data.label) && *quant.is_update.get(str.as_str()).unwrap(){
|
|
|
+ max_buy = Decimal::ZERO;
|
|
|
+ min_sell = Decimal::ZERO;
|
|
|
+ quant.is_update.remove(str.as_str());
|
|
|
+ }
|
|
|
+ let trades: Vec<OriginalTradeGa> = serde_json::from_str(data.data.as_str()).unwrap();
|
|
|
+ for trade in trades {
|
|
|
+ if trade.price > max_buy || max_buy == Decimal::ZERO{
|
|
|
+ max_buy = trade.price
|
|
|
+ }
|
|
|
+ if trade.price < min_sell || min_sell == Decimal::ZERO{
|
|
|
+ min_sell = trade.price
|
|
|
+ }
|
|
|
+ }
|
|
|
+ quant.max_buy_min_sell_cache.insert(data.label, vec![max_buy, min_sell]);
|
|
|
+ } else if data.channel == "orders" {
|
|
|
+ trace_stack.on_before_format();
|
|
|
+ let orders = standard::handle_info::HandleSwapInfo::handle_order(BitgetSpot, data.clone(), multiplier);
|
|
|
+ trace_stack.on_after_format();
|
|
|
+ let mut order_infos:Vec<OrderInfo> = Vec::new();
|
|
|
+ for order in orders.order {
|
|
|
+ if order.status == "NULL" {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ let order_info = OrderInfo {
|
|
|
+ symbol: "".to_string(),
|
|
|
+ amount: order.amount.abs(),
|
|
|
+ side: "".to_string(),
|
|
|
+ price: order.price,
|
|
|
+ client_id: order.custom_id,
|
|
|
+ filled_price: order.avg_price,
|
|
|
+ filled: order.deal_amount.abs(),
|
|
|
+ order_id: order.id,
|
|
|
+ local_time: 0,
|
|
|
+ create_time: 0,
|
|
|
+ status: order.status,
|
|
|
+ fee: Default::default(),
|
|
|
+ trace_stack: Default::default(),
|
|
|
+ };
|
|
|
+ order_infos.push(order_info);
|
|
|
+ }
|
|
|
+ {
|
|
|
+ let mut quant = bot_arc_clone.lock().await;
|
|
|
+ quant.update_order(order_infos, trace_stack);
|
|
|
+ }
|
|
|
+ } else if data.channel == "account" { // _update_account
|
|
|
+ // TODO: 此处应有两个余额,交易币和本位币余额(由于quant中现货的更新账户没有做任何操作,所以此处可暂不处理)
|
|
|
+ let account = standard::handle_info::HandleSwapInfo::handle_account_info(BitgetSpot, data, run_symbol.clone());
|
|
|
+ {
|
|
|
+ let mut quant = bot_arc_clone.lock().await;
|
|
|
+ quant.update_equity(account);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ None => {
|
|
|
+ error!("参考交易所通道错误");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
|
|
|
fn parse_json_array(json: &str) -> serde_json::Result<Vec<Value>> {
|
|
|
serde_json::from_str(json)
|