|
|
@@ -1,4 +1,5 @@
|
|
|
use std::{env, io, thread};
|
|
|
+use std::collections::HashMap;
|
|
|
use ndarray::prelude::*;
|
|
|
use rust_decimal::prelude::{ToPrimitive};
|
|
|
use crate::as_libs::*;
|
|
|
@@ -39,6 +40,7 @@ struct OrderDict {
|
|
|
#[derive(Debug)]
|
|
|
struct OrderInfo {
|
|
|
id: String,
|
|
|
+ buy_price: f64,
|
|
|
sell_price: f64,
|
|
|
time_num: i64
|
|
|
}
|
|
|
@@ -52,7 +54,7 @@ pub struct Bot {
|
|
|
rl_end: f64,
|
|
|
quantity_max: f64,
|
|
|
amount_decimal_places: usize,
|
|
|
- order_info_list: Vec<OrderInfo>,
|
|
|
+ order_info_map: HashMap<String, OrderInfo>,
|
|
|
last_buy_time: i64,
|
|
|
buy_time_limit: i64,
|
|
|
cancel_time_limit: i64,
|
|
|
@@ -66,7 +68,7 @@ pub struct Bot {
|
|
|
impl Bot {
|
|
|
fn new(spread_list: Vec<f64>, symbol: String, limit: i32, short_interval: String,
|
|
|
rl_start: f64, rl_end: f64, quantity_max: f64, amount_decimal_places: usize,
|
|
|
- order_info_list: Vec<OrderInfo>, last_buy_time: i64, buy_time_limit: i64,
|
|
|
+ order_info_map: HashMap<String, OrderInfo>, last_buy_time: i64, buy_time_limit: i64,
|
|
|
cancel_time_limit: i64, price_decimal_places: usize, spread_list_limit: usize) -> Bot {
|
|
|
Bot {
|
|
|
spread_list,
|
|
|
@@ -77,7 +79,7 @@ impl Bot {
|
|
|
rl_end,
|
|
|
quantity_max,
|
|
|
amount_decimal_places,
|
|
|
- order_info_list,
|
|
|
+ order_info_map,
|
|
|
last_buy_time,
|
|
|
buy_time_limit,
|
|
|
cancel_time_limit,
|
|
|
@@ -142,51 +144,48 @@ impl Bot {
|
|
|
return (q, rl_list);
|
|
|
}
|
|
|
|
|
|
- async fn order_list_deal(&mut self, stocks: &f64, exchange: &Exchange) -> Result<i8, io::Error> {
|
|
|
- if self.order_info_list.len() == 0{
|
|
|
+ async fn order_change_response(&mut self, order_info: Order, exchange: &Exchange){
|
|
|
+ if order_info.status.eq("filled") && self.order_info_map.contains_key(&*order_info.id){
|
|
|
+ let order: &OrderInfo = self.order_info_map.get(&*order_info.id).unwrap();
|
|
|
+ // 1.获取账户信息
|
|
|
+ let balance_info = exchange.get_okx_account(&self.symbol).await.unwrap();
|
|
|
+ // 防止有手续费的账户导致的余额小于实际下单数额
|
|
|
+ let order_amount = f64::min(balance_info.stocks, order_info.amount);
|
|
|
+ let id = exchange.place_okx_order(&self.symbol, &"sell".to_string(), &"limit".to_string(), &order.sell_price.to_string(), &order_amount.to_string()).await.unwrap();
|
|
|
+ // 清除已处理订单数据
|
|
|
+ self.order_info_map.remove(&*order_info.id);
|
|
|
+ eprintln!("卖单id: {}", id);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async fn order_list_deal(&mut self, exchange: &Exchange) -> Result<i8, io::Error> {
|
|
|
+ if self.order_info_map.len() == 0{
|
|
|
return Ok(1_i8);
|
|
|
}
|
|
|
let now_time = OffsetDateTime::now_utc().unix_timestamp();
|
|
|
- let mut next_list:Vec<OrderInfo> = vec![];
|
|
|
+ let mut next_list:Vec<String> = vec![];
|
|
|
|
|
|
// 超300s 需取消的订单
|
|
|
- for order in self.order_info_list.iter_mut(){
|
|
|
- eprintln!("order_id: {:?} ", order);
|
|
|
+ for (key, order) in &self.order_info_map {
|
|
|
let order_info: Order = exchange.get_okx_order(&self.symbol, &order.id).await.unwrap();
|
|
|
eprintln!("order_info: {:?}", order_info);
|
|
|
- // 已成交的订单
|
|
|
- if order_info.status.eq("filled"){
|
|
|
- // 防止有手续费的账户导致的余额小于实际下单数额
|
|
|
- let order_amount = f64::min(*stocks, order_info.amount);
|
|
|
- let id = match exchange.place_okx_order(&self.symbol, &"sell".to_string(), &"limit".to_string(), &order.sell_price.to_string(), &order_amount.to_string()).await {
|
|
|
- Ok(m) => m,
|
|
|
- Err(error) => {
|
|
|
- return Err(error);
|
|
|
- }
|
|
|
- };
|
|
|
- eprintln!("卖单id: {}", id);
|
|
|
- } else if order.time_num + self.cancel_time_limit < now_time { // 未成交 && 超时
|
|
|
+ // 未成交 && 超时
|
|
|
+ if !order_info.status.eq("filled") && order.time_num + self.cancel_time_limit < now_time {
|
|
|
let is_success = match exchange. cancel_okx_order(&self.symbol, &order.id).await {
|
|
|
Ok(m) => m,
|
|
|
Err(error) => {
|
|
|
return Err(error);
|
|
|
}
|
|
|
};
|
|
|
+ next_list.push((*key.clone()).parse().unwrap());
|
|
|
// 取消订单,可以在这里执行取消订单的操作
|
|
|
eprintln!("是否成功:{}, 取消订单: {}, 订单下单时间:{}, 现在时间: {}", is_success, order.id, order.time_num, now_time);
|
|
|
- } else {
|
|
|
- // 使用解构复制满足条件的订单
|
|
|
- let new_order = OrderInfo {
|
|
|
- id: order.id.clone(),
|
|
|
- sell_price: order.sell_price,
|
|
|
- time_num: order.time_num
|
|
|
- };
|
|
|
- next_list.push(new_order); // 克隆满足条件的订单并添加到 next_list 中
|
|
|
}
|
|
|
- eprintln!("下轮待确认订单: {:?}", next_list);
|
|
|
}
|
|
|
- self.order_info_list.clear();
|
|
|
- self.order_info_list.extend(next_list);
|
|
|
+ // 清除已处理订单数据
|
|
|
+ for id in next_list.iter() {
|
|
|
+ self.order_info_map.remove(id);
|
|
|
+ }
|
|
|
return Ok(1_i8);
|
|
|
}
|
|
|
|
|
|
@@ -215,7 +214,7 @@ impl Bot {
|
|
|
};
|
|
|
println!("info: {:?}", balance_info);
|
|
|
// 取消超时订单
|
|
|
- self.order_list_deal(&balance_info.stocks, exchange).await.expect("订单信息处理异常!");
|
|
|
+ self.order_list_deal(exchange).await.expect("订单信息处理异常!");
|
|
|
|
|
|
// 2.获取最新k线
|
|
|
let k_line_data = match exchange.get_binance_klines(&self.symbol.to_string(), &self.short_interval, &200).await {
|
|
|
@@ -229,45 +228,47 @@ impl Bot {
|
|
|
|
|
|
let rate :f64 = (q/self.quantity_max) * 100.0;
|
|
|
let index_f :f64 = rl_list.len().to_f64().unwrap() / 100.0 * rate;
|
|
|
- let index = index_f.round().to_usize().unwrap();
|
|
|
+ let index = index_f.to_usize().unwrap();
|
|
|
|
|
|
let order_amount = rl_list.get(index).unwrap().order_amount;
|
|
|
let order_dict :OrderDict = OrderDict{
|
|
|
order_amount,
|
|
|
- buy_price: truncate_decimal_places(rl_list.get(index).unwrap().bid, self.price_decimal_places),
|
|
|
+ buy_price: truncate_decimal_places(rl_list.get(index).unwrap().bid - 100.0, self.price_decimal_places),
|
|
|
sell_price: truncate_decimal_places(rl_list.get(index).unwrap().ask, self.price_decimal_places)
|
|
|
};
|
|
|
+ eprintln!("rl_obj: {:?}", rl_list.get(index));
|
|
|
|
|
|
let now_time = OffsetDateTime::now_utc().unix_timestamp();
|
|
|
// 检测交易间隔,发起交易
|
|
|
- if self.order_info_list.len() > 0 || self.last_buy_time + self.buy_time_limit > now_time {
|
|
|
+ if self.order_info_map.len() > 0 || self.last_buy_time + self.buy_time_limit > now_time {
|
|
|
return Ok(0);
|
|
|
}
|
|
|
// 下单
|
|
|
let buy_order_id = exchange.place_okx_order(&self.symbol, &"buy".to_string(), &"limit".to_string(), &order_dict.buy_price.to_string(), &order_dict.order_amount.to_string()).await.unwrap();
|
|
|
let order = OrderInfo{
|
|
|
- id: buy_order_id,
|
|
|
+ id: buy_order_id.clone(),
|
|
|
+ buy_price: order_dict.buy_price,
|
|
|
sell_price: order_dict.sell_price,
|
|
|
time_num: now_time
|
|
|
};
|
|
|
eprintln!("buy_order: {:?}", order);
|
|
|
- self.order_info_list.push(order);
|
|
|
+ self.order_info_map.insert(buy_order_id, order);
|
|
|
self.last_buy_time = now_time;
|
|
|
|
|
|
return Ok(0);
|
|
|
}
|
|
|
|
|
|
- fn depth_handler(&self, depth: Depth) {
|
|
|
- println!("{:?}", depth)
|
|
|
+ fn depth_handler(&mut self, depth: Depth) {
|
|
|
+ // println!("{:?}", depth)
|
|
|
|
|
|
- // let (spread, mid_price, ask, bid) = get_spread(depth);
|
|
|
- // self.mid_price = mid_price;
|
|
|
- // self.ask = ask;
|
|
|
- // self.bid = bid;
|
|
|
- // if self.spread_list.len() > self.spread_list_limit {
|
|
|
- // self.spread_list.remove(0);
|
|
|
- // }
|
|
|
- // self.spread_list.push(spread);
|
|
|
+ let (spread, mid_price, ask, bid) = get_spread(&depth);
|
|
|
+ self.mid_price = mid_price;
|
|
|
+ self.ask = ask;
|
|
|
+ self.bid = bid;
|
|
|
+ if self.spread_list.len() > self.spread_list_limit {
|
|
|
+ self.spread_list.remove(0);
|
|
|
+ }
|
|
|
+ self.spread_list.push(spread);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -287,8 +288,8 @@ async fn main() {
|
|
|
let quantity_max = 20.0;
|
|
|
// 交易数量小数位数
|
|
|
let amount_decimal_places: usize = 8;
|
|
|
- // 订单信息list
|
|
|
- let order_info_list:Vec<OrderInfo> = Vec::new();
|
|
|
+ // 订单信息map
|
|
|
+ let order_info_map:HashMap<String, OrderInfo> = HashMap::new();
|
|
|
// 最后买入时间
|
|
|
let last_buy_time:i64 = 1;
|
|
|
// 下单时间间隔
|
|
|
@@ -307,7 +308,7 @@ async fn main() {
|
|
|
let okx_passphrase= env::var("okx_passphrase").unwrap();
|
|
|
let exchange:Exchange = Exchange::new(okx_access_key, okx_secret_key, okx_passphrase);
|
|
|
|
|
|
- let bot = Bot::new(spread_list, symbol.clone(), limit, short_interval, rl_start, rl_end, quantity_max, amount_decimal_places, order_info_list, last_buy_time, buy_time_limit, cancel_time_limit, price_decimal_places, spread_list_limit);
|
|
|
+ let bot = Bot::new(spread_list, symbol.clone(), limit, short_interval, rl_start, rl_end, quantity_max, amount_decimal_places, order_info_map, last_buy_time, buy_time_limit, cancel_time_limit, price_decimal_places, spread_list_limit);
|
|
|
let bot_arc = Arc::new(Mutex::new(bot));
|
|
|
let bot_binance_depth_arc = Arc::clone(&bot_arc);
|
|
|
|