|
|
@@ -1,9 +1,11 @@
|
|
|
-use std::io;
|
|
|
+use std::{env, io};
|
|
|
+use chrono::format::Item::Error;
|
|
|
use ndarray::prelude::*;
|
|
|
-use rust_decimal::prelude::{ToPrimitive, Zero};
|
|
|
+use rust_decimal::prelude::{ToPrimitive};
|
|
|
use crate::as_libs::*;
|
|
|
-use crate::exchange_middle_ware::{Account, cancel_okx_order, get_binance_depth, get_binance_klines, get_okx_account, get_okx_order, Order, place_okx_order, Record};
|
|
|
+use crate::exchange_middle_ware::{Account, Depth, Exchange, Order, Record};
|
|
|
use time::OffsetDateTime;
|
|
|
+use crate::exchange_libs::is_proxy;
|
|
|
|
|
|
mod as_libs;
|
|
|
mod exchange_libs;
|
|
|
@@ -52,11 +54,18 @@ struct Bot {
|
|
|
last_buy_time: i64,
|
|
|
buy_time_limit: i64,
|
|
|
cancel_time_limit: i64,
|
|
|
- price_decimal_places: usize
|
|
|
+ price_decimal_places: usize,
|
|
|
+ mid_price: f64,
|
|
|
+ ask: f64,
|
|
|
+ bid: f64,
|
|
|
+ spread_list_limit: usize
|
|
|
}
|
|
|
|
|
|
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, cancel_time_limit: i64, price_decimal_places: usize) -> 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,
|
|
|
+ cancel_time_limit: i64, price_decimal_places: usize, spread_list_limit: usize) -> Bot {
|
|
|
Bot {
|
|
|
spread_list,
|
|
|
symbol,
|
|
|
@@ -70,32 +79,49 @@ impl Bot {
|
|
|
last_buy_time,
|
|
|
buy_time_limit,
|
|
|
cancel_time_limit,
|
|
|
- price_decimal_places
|
|
|
+ price_decimal_places,
|
|
|
+ mid_price: 0.0,
|
|
|
+ ask: 0.0,
|
|
|
+ bid: 0.0,
|
|
|
+ spread_list_limit
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ fn depth_handler(&mut self, depth: &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);
|
|
|
}
|
|
|
|
|
|
async fn start(&mut self){
|
|
|
- while true {
|
|
|
- let f = match self.do_logic().await {
|
|
|
+ is_proxy();
|
|
|
+ // 使用std::env::var函数获取环境变量的值
|
|
|
+ let okx_access_key= env::var("okx_access_key").unwrap();
|
|
|
+ let okx_secret_key= env::var("okx_secret_key").unwrap();
|
|
|
+ let okx_passphrase= env::var("okx_passphrase").unwrap();
|
|
|
+
|
|
|
+ let exchange:Exchange = Exchange::new(okx_access_key, okx_secret_key, okx_passphrase);
|
|
|
+ let bot = self;
|
|
|
+ let get_depth_fn = |depth:&Depth| Self::depth_handler(&mut *bot, depth);
|
|
|
+ exchange.get_binance_depth(&bot.symbol, 10, get_depth_fn).await;
|
|
|
+
|
|
|
+ loop {
|
|
|
+ let f = match bot.do_logic(&exchange).await {
|
|
|
Ok(m) => m,
|
|
|
Err(error) => {
|
|
|
+ eprintln!("异常出现,捕获异常: {}", error);
|
|
|
1
|
|
|
},
|
|
|
};
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- async fn do_logic(&mut self) -> Result<i8, io::Error>{
|
|
|
- let depth = get_binance_depth(&self.symbol, self.limit).await;
|
|
|
-
|
|
|
- // 1.获取最新spread,如何将主逻辑和spread(ws推送方式)关联起来
|
|
|
- let (spread, mid_price, ask, bid) = get_spread(&depth);
|
|
|
-
|
|
|
- if self.spread_list.len() > 300 {
|
|
|
- self.spread_list.remove(0);
|
|
|
- }
|
|
|
- self.spread_list.push(spread);
|
|
|
-
|
|
|
+ async fn do_logic(&mut self, exchange: &Exchange) -> Result<i8, io::Error>{
|
|
|
// 使用 max_by 方法和 partial_cmp 进行比较
|
|
|
let max_option = self.spread_list.iter().max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
|
|
|
match max_option {
|
|
|
@@ -105,17 +131,28 @@ impl Bot {
|
|
|
let max_spread = *max_option.unwrap();
|
|
|
|
|
|
if self.spread_list.len() < 10 {
|
|
|
-
|
|
|
+ println!()
|
|
|
} else {
|
|
|
// 1.获取账户信息
|
|
|
- let balance_info = get_okx_account(&self.symbol).await;
|
|
|
+ let balance_info = match exchange.get_okx_account(&self.symbol).await {
|
|
|
+ Ok(m) => m,
|
|
|
+ Err(error) => {
|
|
|
+ return Err(error);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ println!("info: {:?}", balance_info);
|
|
|
// 取消超时订单
|
|
|
- self.order_list_deal(&balance_info.stocks).await;
|
|
|
+ self.order_list_deal(&balance_info.stocks, exchange).await.expect("订单信息处理异常!");
|
|
|
|
|
|
// 2.获取最新k线
|
|
|
- let k_line_data = get_binance_klines(&self.symbol.to_string(), &self.short_interval, &200).await;
|
|
|
+ let k_line_data = match exchange.get_binance_klines(&self.symbol.to_string(), &self.short_interval, &200).await {
|
|
|
+ Ok(m) => m,
|
|
|
+ Err(error) => {
|
|
|
+ return Err(error);
|
|
|
+ }
|
|
|
+ };
|
|
|
// rl_list 计算
|
|
|
- let (q, rl_list) = self.calc_params(&k_line_data, balance_info, max_spread, mid_price, bid, ask);
|
|
|
+ let (q, rl_list) = self.calc_params(&k_line_data, balance_info, max_spread);
|
|
|
|
|
|
let rate :f64 = (q/self.quantity_max) * 100.0;
|
|
|
let index_f :f64 = rl_list.len().to_f64().unwrap() / 100.0 * rate;
|
|
|
@@ -134,7 +171,7 @@ impl Bot {
|
|
|
return Ok(0);
|
|
|
}
|
|
|
// 下单
|
|
|
- let buy_order_id = place_okx_order(&self.symbol, &"buy".to_string(), &"limit".to_string(), &order_dict.buy_price.to_string(), &order_dict.order_amount.to_string()).await;
|
|
|
+ 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,
|
|
|
sell_price: order_dict.sell_price,
|
|
|
@@ -144,15 +181,15 @@ impl Bot {
|
|
|
self.order_info_list.push(order);
|
|
|
self.last_buy_time = now_time;
|
|
|
}
|
|
|
- return Ok(1);
|
|
|
+ return Ok(0);
|
|
|
}
|
|
|
|
|
|
- fn calc_params(&self, k_line_data: &Vec<Record>, balance_info: Account, max_spread: f64, mid_price:f64, bid: f64, ask: f64) -> (f64, Vec<RiskLevel>){
|
|
|
+ fn calc_params(&self, k_line_data: &Vec<Record>, balance_info: Account, max_spread: f64) -> (f64, Vec<RiskLevel>){
|
|
|
// 计算最近20根K线的标准差
|
|
|
// 3.获取标准差数组的最后一个值
|
|
|
let last_std = std_n_by_records(k_line_data, 20);
|
|
|
// 4.计算库存资产折合本位币价值
|
|
|
- let mut q = (balance_info.stocks + balance_info.frozen_stocks) * mid_price;
|
|
|
+ let mut q = (balance_info.stocks + balance_info.frozen_stocks) * self.mid_price;
|
|
|
if q < 1.0 {
|
|
|
q = 1.0;
|
|
|
}
|
|
|
@@ -167,9 +204,9 @@ impl Bot {
|
|
|
// 7.获取dd
|
|
|
let dd = calc_deviation_range(self.rl_end, &self.spread_list, *i);
|
|
|
// 8.获取Reservation price 预定价格
|
|
|
- let rp = calc_rp(mid_price, q, *i, gamma, last_std);
|
|
|
+ let rp = calc_rp(self.mid_price, q, *i, gamma, last_std);
|
|
|
// eprintln!("rp {}, dd {}, ask {}, bid {}", rp, dd, ask, bid);
|
|
|
- if (rp + 0.5 * dd) < ask || (rp - 0.5 * dd) > bid {
|
|
|
+ if (rp + 0.5 * dd) < self.ask || (rp - 0.5 * dd) > self.bid {
|
|
|
continue;
|
|
|
}
|
|
|
// 9.获取dk,用于计算e的dk次方
|
|
|
@@ -181,16 +218,16 @@ impl Bot {
|
|
|
// 11.获取theta
|
|
|
let cal_theta = calc_theta(gamma, last_std, kappa, *i);
|
|
|
// 交易数量
|
|
|
- let order_amount = calc_order_amount(self.rl_end, *i, q, self.quantity_max, bid, self.amount_decimal_places);
|
|
|
+ let order_amount = calc_order_amount(self.rl_end, *i, q, self.quantity_max, self.bid, self.amount_decimal_places);
|
|
|
let rl_info = RiskLevel{
|
|
|
gamma: gamma*i,
|
|
|
- mid_price,
|
|
|
+ mid_price: self.mid_price,
|
|
|
rp,
|
|
|
theta_a_b_half: 0.5*dd,
|
|
|
bid: rp - cal_theta,
|
|
|
- bid_best: bid,
|
|
|
+ bid_best: self.bid,
|
|
|
ask: rp + cal_theta,
|
|
|
- ask_best: ask,
|
|
|
+ ask_best: self.ask,
|
|
|
kappa,
|
|
|
cal_theta,
|
|
|
order_amount
|
|
|
@@ -200,9 +237,9 @@ impl Bot {
|
|
|
return (q, rl_list);
|
|
|
}
|
|
|
|
|
|
- async fn order_list_deal(&mut self, stocks: &f64){
|
|
|
+ async fn order_list_deal(&mut self, stocks: &f64, exchange: &Exchange) -> Result<i8, io::Error> {
|
|
|
if self.order_info_list.len() == 0{
|
|
|
- return;
|
|
|
+ return Ok(1_i8);
|
|
|
}
|
|
|
let now_time = OffsetDateTime::now_utc().unix_timestamp();
|
|
|
let mut next_list:Vec<OrderInfo> = vec![];
|
|
|
@@ -210,18 +247,28 @@ impl Bot {
|
|
|
// 超300s 需取消的订单
|
|
|
for order in self.order_info_list.iter_mut(){
|
|
|
eprintln!("order_id: {:?} ", order);
|
|
|
- let order_info: Order = get_okx_order(&self.symbol, &order.id).await;
|
|
|
+ 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 = place_okx_order(&self.symbol, &"sell".to_string(), &"limit".to_string(), &order.sell_price.to_string(), &order_amount.to_string()).await;
|
|
|
+ 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 { // 未成交 && 超时
|
|
|
- cancel_okx_order(&self.symbol, &order.id).await;
|
|
|
+ let is_success = match exchange. cancel_okx_order(&self.symbol, &order.id).await {
|
|
|
+ Ok(m) => m,
|
|
|
+ Err(error) => {
|
|
|
+ return Err(error);
|
|
|
+ }
|
|
|
+ };
|
|
|
// 取消订单,可以在这里执行取消订单的操作
|
|
|
- eprintln!("取消订单: {}, 订单下单时间:{}, 现在时间: {}", order.id, order.time_num, now_time);
|
|
|
+ eprintln!("是否成功:{}, 取消订单: {}, 订单下单时间:{}, 现在时间: {}", is_success, order.id, order.time_num, now_time);
|
|
|
} else {
|
|
|
// 使用解构复制满足条件的订单
|
|
|
let new_order = OrderInfo {
|
|
|
@@ -235,8 +282,10 @@ impl Bot {
|
|
|
}
|
|
|
self.order_info_list.clear();
|
|
|
self.order_info_list.extend(next_list);
|
|
|
+ return Ok(1_i8);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -268,9 +317,10 @@ async fn main() {
|
|
|
let cancel_time_limit = 30;
|
|
|
// 价格小数位数
|
|
|
let price_decimal_places = 2;
|
|
|
+ // spread_list_limit 长度限制
|
|
|
+ let spread_list_limit = 10;
|
|
|
|
|
|
-
|
|
|
- let mut bot = Bot::new(spread_list, symbol, 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);
|
|
|
+ let mut bot = Bot::new(spread_list, symbol, 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);
|
|
|
bot.start().await;
|
|
|
|
|
|
}
|