JiahengHe 2 ani în urmă
părinte
comite
350b593136
3 a modificat fișierele cu 326 adăugiri și 203 ștergeri
  1. 7 6
      src/as_libs.rs
  2. 272 197
      src/main.rs
  3. 47 0
      tests/main_test.rs

+ 7 - 6
src/as_libs.rs

@@ -77,8 +77,9 @@ pub fn calc_theta(gamma: f64, std: f64, kappa: f64, ira: f64) -> f64 {
 // 给定ira、当前库存、最大库存、买入价格、下单数量小数位数,计算合理下单数量
 // 给定ira、当前库存、最大库存、买入价格、下单数量小数位数,计算合理下单数量
 // 下单数量要与ira(风险系数)、quantity(库存)成反比
 // 下单数量要与ira(风险系数)、quantity(库存)成反比
 pub fn calc_order_amount(ira_max: f64, ira: f64, quantity: f64, quantity_max: f64, bid_price: f64, amount_decimal_places: usize) -> f64 {
 pub fn calc_order_amount(ira_max: f64, ira: f64, quantity: f64, quantity_max: f64, bid_price: f64, amount_decimal_places: usize) -> f64 {
-    let eta = (ira_max / (ira + 1.0)) / (quantity * 2.0);
-    let order_value = (-quantity_max * eta).abs();
+    let eta = (ira / ira_max) / (1.0 + quantity * 2.0);
+    let order_value_base = (-quantity * eta).abs();
+    let order_value = (quantity_max * 1.0/50.0) * (1.0 - order_value_base / quantity_max);
     let order_amount = order_value / bid_price;
     let order_amount = order_value / bid_price;
 
 
     return truncate_decimal_places(order_amount, amount_decimal_places);
     return truncate_decimal_places(order_amount, amount_decimal_places);
@@ -187,10 +188,10 @@ mod tests {
 
 
     #[test]
     #[test]
     fn test_calc_order_amount() {
     fn test_calc_order_amount() {
-        let quantity = 400.0;
-        let quantity_max = 1000.0;
-        let bid_price = 30000.0;
-        let amount_decimal_places = 4;
+        let quantity = 10.0;
+        let quantity_max = 20.0;
+        let bid_price = 28684.0;
+        let amount_decimal_places = 8;
 
 
         let start = 0.1;
         let start = 0.1;
         let end = 10.0;
         let end = 10.0;

+ 272 - 197
src/main.rs

@@ -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_libs;
 mod exchange_middle_ware;
 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: "),
-//         // }
-//
-//     }
-//
-// }

+ 47 - 0
tests/main_test.rs

@@ -0,0 +1,47 @@
+use std::io;
+use std::ops::Add;
+use rust_decimal::prelude::ToPrimitive;
+use time::OffsetDateTime;
+
+#[derive(Debug)]
+struct OrderInfo {
+    id: String,
+    sell_price: f64,
+    time_num: i64
+}
+
+fn add_aa(x: &mut i64) -> Result<i64, io::Error>{
+    let mut i:i64 = OffsetDateTime::now_utc().unix_timestamp();
+
+    if i < 0{
+        println!("1231");
+        *x = i;
+        Ok(0)
+    } else {
+        Err(io::Error::new(io::ErrorKind::Other, "错了"))
+    }
+}
+
+#[tokio::test]
+async fn test(){
+    // let mut now_time = OffsetDateTime::now_utc().unix_timestamp();
+    // let mut last_time = now_time;
+    // while true {
+    //     if(now_time < last_time + 5){
+    //         now_time = OffsetDateTime::now_utc().unix_timestamp();
+    //     }else{
+    //         last_time = now_time+5;
+    //         println!("30s 后:{}", now_time);
+    //         return;
+    //     }
+    // }
+    let mut x: i64 = 64;
+    let f = match add_aa(&mut x) {
+        Ok(m) => m,
+        Err(error) => {
+            1
+        },
+    };
+
+    println!("f: {}", f);
+}