|
|
@@ -1,201 +1,276 @@
|
|
|
+use std::io;
|
|
|
+use ndarray::prelude::*;
|
|
|
+use rust_decimal::prelude::{ToPrimitive, Zero};
|
|
|
+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 time::OffsetDateTime;
|
|
|
+
|
|
|
+mod as_libs;
|
|
|
mod exchange_libs;
|
|
|
mod exchange_middle_ware;
|
|
|
-use time::OffsetDateTime;
|
|
|
-fn main() {
|
|
|
+
|
|
|
+#[derive(Debug)]
|
|
|
+struct RiskLevel{
|
|
|
+ gamma: f64,
|
|
|
+ mid_price: f64,
|
|
|
+ rp: f64,
|
|
|
+ theta_a_b_half: f64,
|
|
|
+ bid: f64,
|
|
|
+ bid_best: f64,
|
|
|
+ ask: f64,
|
|
|
+ ask_best: f64,
|
|
|
+ kappa: f64,
|
|
|
+ cal_theta: f64,
|
|
|
+ order_amount: f64
|
|
|
+}
|
|
|
+
|
|
|
+#[derive(Debug)]
|
|
|
+struct OrderDict {
|
|
|
+ order_amount: f64,
|
|
|
+ buy_price: f64,
|
|
|
+ sell_price: f64
|
|
|
+}
|
|
|
+// 订单信息
|
|
|
+
|
|
|
+#[derive(Debug)]
|
|
|
+struct OrderInfo {
|
|
|
+ id: String,
|
|
|
+ sell_price: f64,
|
|
|
+ time_num: i64
|
|
|
+}
|
|
|
+
|
|
|
+struct Bot {
|
|
|
+ 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
|
|
|
+}
|
|
|
+
|
|
|
+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 {
|
|
|
+ Bot {
|
|
|
+ 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
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async fn start(&mut self){
|
|
|
+ while true {
|
|
|
+ let f = match self.do_logic().await {
|
|
|
+ Ok(m) => m,
|
|
|
+ Err(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);
|
|
|
+
|
|
|
+ // 使用 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 {
|
|
|
+ Some(max_value) => { },
|
|
|
+ None => eprintln!("列表为空"),
|
|
|
+ }
|
|
|
+ let max_spread = *max_option.unwrap();
|
|
|
+
|
|
|
+ if self.spread_list.len() < 10 {
|
|
|
+
|
|
|
+ } else {
|
|
|
+ // 1.获取账户信息
|
|
|
+ let balance_info = get_okx_account(&self.symbol).await;
|
|
|
+ // 取消超时订单
|
|
|
+ self.order_list_deal(&balance_info.stocks).await;
|
|
|
+
|
|
|
+ // 2.获取最新k线
|
|
|
+ let k_line_data = get_binance_klines(&self.symbol.to_string(), &self.short_interval, &200).await;
|
|
|
+ // rl_list 计算
|
|
|
+ let (q, rl_list) = self.calc_params(&k_line_data, balance_info, max_spread, mid_price, bid, ask);
|
|
|
+
|
|
|
+ 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 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),
|
|
|
+ sell_price: truncate_decimal_places(rl_list.get(index).unwrap().ask, self.price_decimal_places)
|
|
|
+ };
|
|
|
+
|
|
|
+ let now_time = OffsetDateTime::now_utc().unix_timestamp();
|
|
|
+ // TODO: 检测交易间隔,发起交易
|
|
|
+ if self.order_info_list.len() > 0 || self.last_buy_time + self.buy_time_limit > now_time {
|
|
|
+ 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 order = OrderInfo{
|
|
|
+ id: buy_order_id,
|
|
|
+ sell_price: order_dict.sell_price,
|
|
|
+ time_num: now_time
|
|
|
+ };
|
|
|
+ eprintln!("buy_order: {:?}", order);
|
|
|
+ self.order_info_list.push(order);
|
|
|
+ self.last_buy_time = now_time;
|
|
|
+ }
|
|
|
+ return Ok(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ 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>){
|
|
|
+ // 计算最近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;
|
|
|
+ if q < 1.0 {
|
|
|
+ q = 1.0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5.计算gamma值
|
|
|
+ let gamma = calc_gamma(max_spread, q, last_std);
|
|
|
+
|
|
|
+ // 6.生成等差数列
|
|
|
+ let rl = Array::linspace(self.rl_start, self.rl_end, 50).into_owned();
|
|
|
+ let mut rl_list: Vec<RiskLevel> = Vec::new();
|
|
|
+ for i in rl.iter(){
|
|
|
+ // 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);
|
|
|
+ // eprintln!("rp {}, dd {}, ask {}, bid {}", rp, dd, ask, bid);
|
|
|
+ if (rp + 0.5 * dd) < ask || (rp - 0.5 * dd) > bid {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 9.获取dk,用于计算e的dk次方
|
|
|
+ let dk = calc_dk(dd, gamma, last_std, *i);
|
|
|
+ // eprintln!("dk {}", dk);
|
|
|
+ // 10.获取kappa
|
|
|
+ let kappa = calc_kappa(gamma, dk, dd, *i);
|
|
|
+ // eprintln!("kappa {}", kappa);
|
|
|
+ // 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 rl_info = RiskLevel{
|
|
|
+ gamma: gamma*i,
|
|
|
+ mid_price,
|
|
|
+ rp,
|
|
|
+ theta_a_b_half: 0.5*dd,
|
|
|
+ bid: rp - cal_theta,
|
|
|
+ bid_best: bid,
|
|
|
+ ask: rp + cal_theta,
|
|
|
+ ask_best: ask,
|
|
|
+ kappa,
|
|
|
+ cal_theta,
|
|
|
+ order_amount
|
|
|
+ };
|
|
|
+ rl_list.push(rl_info);
|
|
|
+ }
|
|
|
+ return (q, rl_list);
|
|
|
+ }
|
|
|
+
|
|
|
+ async fn order_list_deal(&mut self, stocks: &f64){
|
|
|
+ if self.order_info_list.len() == 0{
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let now_time = OffsetDateTime::now_utc().unix_timestamp();
|
|
|
+ let mut next_list:Vec<OrderInfo> = vec![];
|
|
|
+
|
|
|
+ // 超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;
|
|
|
+ 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;
|
|
|
+ eprintln!("卖单id: {}", id);
|
|
|
+ } else if order.time_num + self.cancel_time_limit < now_time { // 未成交 && 超时
|
|
|
+ cancel_okx_order(&self.symbol, &order.id).await;
|
|
|
+ // 取消订单,可以在这里执行取消订单的操作
|
|
|
+ eprintln!("取消订单: {}, 订单下单时间:{}, 现在时间: {}", 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);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+#[tokio::main]
|
|
|
+async fn main() {
|
|
|
+
|
|
|
+ let spread_list:Vec<f64> = Vec::new();
|
|
|
+ // 币对-获取深度信息参数
|
|
|
+ let symbol:String = "BTC_USDT".to_string();
|
|
|
+ // 限制数-获取深度信息参数
|
|
|
+ let limit = 10;
|
|
|
+ // 开始
|
|
|
+ let rl_start= 0.0;
|
|
|
+ // 结束
|
|
|
+ let rl_end= 20.0;
|
|
|
+ let short_interval = "5m".to_string();
|
|
|
+ // 最大库存
|
|
|
+ let quantity_max = 20.0;
|
|
|
+ // 交易数量小数位数
|
|
|
+ let amount_decimal_places: usize = 8;
|
|
|
+ // 订单信息list
|
|
|
+ let order_info_list:Vec<OrderInfo> = Vec::new();
|
|
|
+ // 最后买入时间
|
|
|
+ let last_buy_time:i64 = 1;
|
|
|
+ // 下单时间间隔
|
|
|
+ let buy_time_limit = 20;
|
|
|
+ // 取消订单时间间隔
|
|
|
+ let cancel_time_limit = 30;
|
|
|
+ // 价格小数位数
|
|
|
+ let price_decimal_places = 2;
|
|
|
+
|
|
|
+
|
|
|
+ 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);
|
|
|
+ bot.start().await;
|
|
|
|
|
|
}
|
|
|
-//
|
|
|
-// use ndarray::prelude::*;
|
|
|
-// use rust_decimal::prelude::ToPrimitive;
|
|
|
-// use crate::as_libs::*;
|
|
|
-// use crate::exchange_middle_ware::{Account, get_binance_depth, get_binance_klines, get_okx_account, Record};
|
|
|
-// use time::OffsetDateTime;
|
|
|
-//
|
|
|
-// mod as_libs;
|
|
|
-// mod exchange_libs;
|
|
|
-// mod exchange_middle_ware;
|
|
|
-//
|
|
|
-// #[derive(Debug)]
|
|
|
-// struct Ira{
|
|
|
-// ira: f64,
|
|
|
-// gamma: f64,
|
|
|
-// mid_price: f64,
|
|
|
-// rp: f64,
|
|
|
-// theta_a_b_half: f64,
|
|
|
-// bid: f64,
|
|
|
-// bid_best: f64,
|
|
|
-// ask: f64,
|
|
|
-// ask_best: f64,
|
|
|
-// kappa: f64,
|
|
|
-// cal_theta: f64
|
|
|
-// }
|
|
|
-//
|
|
|
-// #[derive(Debug)]
|
|
|
-// struct OrderDict {
|
|
|
-// zj: f64,
|
|
|
-// buy_price: f64,
|
|
|
-// sell_price: f64
|
|
|
-// }
|
|
|
-// // 订单信息
|
|
|
-//
|
|
|
-// #[derive(Debug)]
|
|
|
-// struct OrderInfo {
|
|
|
-// id: String,
|
|
|
-// time_num: i64
|
|
|
-// }
|
|
|
-//
|
|
|
-//
|
|
|
-// fn calc_params(k_line_data:&Vec<Record>, balance_info: &Account, mid_price: f64, max_spread: f64, ira_start: f64, ira_end: f64, spread_list: &mut Vec<f64>, ask: f64, bid: f64) -> (f64, Vec<Ira>){
|
|
|
-// // 计算最近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;
|
|
|
-// if q == 0.0{
|
|
|
-// q = 10.0;
|
|
|
-// }
|
|
|
-// // 5.计算gamma值
|
|
|
-// let gamma = calc_gamma(max_spread, q, last_std);
|
|
|
-// // 6.生成等差数列
|
|
|
-// let ira = Array::linspace(ira_start, ira_end, 50).into_owned();
|
|
|
-// let mut ira_list: Vec<Ira> = Vec::new();
|
|
|
-// for i in ira.iter(){
|
|
|
-// // 7.获取dd
|
|
|
-// let dd = calc_deviation_range(ira_end, spread_list, *i);
|
|
|
-// // 8.获取Reservation price 预定价格
|
|
|
-// let rp = calc_rp(mid_price, q, *i, gamma, last_std);
|
|
|
-// if (rp + 0.5 * dd) < ask || (rp - 0.5 * dd) > bid {
|
|
|
-// continue;
|
|
|
-// }
|
|
|
-// // 9.获取dk,用于计算e的dk次方
|
|
|
-// let dk = calc_dk(dd, gamma, last_std, *i);
|
|
|
-// // 10.获取kappa
|
|
|
-// let kappa = calc_kappa(gamma, dk, dd, *i);
|
|
|
-// // 11.获取theta
|
|
|
-// let cal_theta = calc_theta(gamma, last_std, kappa, *i);
|
|
|
-// let ira_info = Ira{
|
|
|
-// ira: *i,
|
|
|
-// gamma: gamma*i,
|
|
|
-// mid_price,
|
|
|
-// rp,
|
|
|
-// theta_a_b_half: 0.5*dd,
|
|
|
-// bid: rp - cal_theta,
|
|
|
-// bid_best: bid,
|
|
|
-// ask: rp + cal_theta,
|
|
|
-// ask_best: ask,
|
|
|
-// kappa,
|
|
|
-// cal_theta
|
|
|
-// };
|
|
|
-// ira_list.push(ira_info);
|
|
|
-// }
|
|
|
-// return (q, ira_list);
|
|
|
-// }
|
|
|
-//
|
|
|
-// fn order_list_deal(order_info_list: &mut Vec<OrderInfo>){
|
|
|
-// if order_info_list.len() == 0{
|
|
|
-// return;
|
|
|
-// }
|
|
|
-// let now_time = OffsetDateTime::now_utc().unix_timestamp();
|
|
|
-// let mut next_list:Vec<OrderInfo> = vec![];
|
|
|
-//
|
|
|
-// // 超300s 需取消的订单
|
|
|
-// for order in order_info_list.iter_mut(){
|
|
|
-// if order.time_num + 300 <= now_time {
|
|
|
-// // 取消订单,可以在这里执行取消订单的操作
|
|
|
-// println!("取消订单: {}", order.id);
|
|
|
-// } else {
|
|
|
-// // 使用解构复制满足条件的订单
|
|
|
-// let new_order = OrderInfo {
|
|
|
-// id: order.id.clone(),
|
|
|
-// time_num: order.time_num
|
|
|
-// };
|
|
|
-// next_list.push(new_order); // 克隆满足条件的订单并添加到 next_list 中
|
|
|
-// }
|
|
|
-// }
|
|
|
-// order_info_list.clear();
|
|
|
-// order_info_list.extend(next_list);
|
|
|
-// }
|
|
|
-//
|
|
|
-// async fn do_logic(spread_list: &mut Vec<f64>, symbol: &String, limit: i32, short_interval: &String, ira_start: f64, ira_end: f64, quantity_max: f64, amount_decimal_places: usize, order_info_list: &mut Vec<OrderInfo>) -> i8{
|
|
|
-// let depth = get_binance_depth(&symbol, limit).await;
|
|
|
-//
|
|
|
-// // 1.获取最新spread,如何将主逻辑和spread(ws推送方式)关联起来
|
|
|
-// let (spread, mid_price, ask, bid) = get_spread(&depth);
|
|
|
-//
|
|
|
-// if spread_list.len() > 300 {
|
|
|
-// spread_list.remove(0);
|
|
|
-// }
|
|
|
-// spread_list.push(spread);
|
|
|
-//
|
|
|
-// // 使用 max_by 方法和 partial_cmp 进行比较
|
|
|
-// let max_option = spread_list.iter().max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
|
|
|
-// match max_option {
|
|
|
-// Some(max_value) => println!("最大值是: {}", max_value),
|
|
|
-// None => println!("列表为空"),
|
|
|
-// }
|
|
|
-// let max_spread = *max_option.unwrap();
|
|
|
-// println!("max_spread: {}", max_spread);
|
|
|
-//
|
|
|
-// if spread_list.len() >= 10 {
|
|
|
-//
|
|
|
-// } else {
|
|
|
-// // 1.获取账户信息
|
|
|
-// let balance_info = get_okx_account(symbol).await;
|
|
|
-// // 2.获取最新k线
|
|
|
-// let k_line_data = get_binance_klines(&symbol.to_string(), &short_interval, &200).await;
|
|
|
-// // ira_list 计算
|
|
|
-// let (q, ira_list) = calc_params(&k_line_data, &balance_info, mid_price, max_spread, ira_start, ira_end, spread_list, ask, bid);
|
|
|
-// println!("q: {}", q);
|
|
|
-// println!("ira_list: {:?}", ira_list);
|
|
|
-//
|
|
|
-// let rate :f64 = 50.0;
|
|
|
-// let index_f :f64 = ira_list.len().to_f64().unwrap() / 100.0 * rate;
|
|
|
-// let index = index_f.round().to_usize().unwrap();
|
|
|
-// println!("index: {}", index);
|
|
|
-//
|
|
|
-// let zj = calc_order_amount(ira_end, ira_list.get(index).unwrap().ira, q, quantity_max, ira_list.get(index).unwrap().bid, amount_decimal_places);
|
|
|
-// let order_dict :OrderDict = OrderDict{
|
|
|
-// zj,
|
|
|
-// buy_price: truncate_decimal_places(ira_list.get(index).unwrap().bid, 2),
|
|
|
-// sell_price: truncate_decimal_places(ira_list.get(index).unwrap().ask, 2)
|
|
|
-// };
|
|
|
-// println!("order_dict: {:?}", order_dict);
|
|
|
-//
|
|
|
-// // TODO: 发起交易
|
|
|
-// }
|
|
|
-//
|
|
|
-// // 取消超时订单
|
|
|
-// order_list_deal(order_info_list);
|
|
|
-// return 1;
|
|
|
-// }
|
|
|
-//
|
|
|
-// #[tokio::main]
|
|
|
-// async fn main() {
|
|
|
-// let mut spreadlist:Vec<f64> = Vec::new();
|
|
|
-// // 币对-获取深度信息参数
|
|
|
-// let symbol:String = "btc_usdt".to_string();
|
|
|
-// // 限制数-获取深度信息参数
|
|
|
-// let limit = 12;
|
|
|
-// // 开始
|
|
|
-// let ira_start= 0.0;
|
|
|
-// // 结束
|
|
|
-// let ira_end= 20.0;
|
|
|
-// let short_interval = "5m".to_string();
|
|
|
-// // 最大库存
|
|
|
-// let quantity_max = 50.0;
|
|
|
-//
|
|
|
-// let amount_decimal_places: usize = 2;
|
|
|
-// // 订单信息list
|
|
|
-// let mut order_info_list:Vec<OrderInfo> = Vec::new();
|
|
|
-//
|
|
|
-// while true {
|
|
|
-// do_logic(&mut spreadlist, &symbol, limit, &short_interval, ira_start, ira_end, quantity_max, amount_decimal_places, &mut order_info_list).await;
|
|
|
-//
|
|
|
-// // match future_result {
|
|
|
-// // Ok(value) => println!("Result: "),
|
|
|
-// // Err(error) => println!("Error: "),
|
|
|
-// // }
|
|
|
-//
|
|
|
-// }
|
|
|
-//
|
|
|
-// }
|