|
|
@@ -180,8 +180,8 @@ struct SwapAccountDetails {
|
|
|
#[derive(Debug, Deserialize, Serialize)]
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
pub struct SwapPosition {
|
|
|
- pub adl: Decimal,
|
|
|
- pub avail_pos: Decimal,
|
|
|
+ pub adl: String,
|
|
|
+ pub avail_pos: String,
|
|
|
pub avg_px: Decimal,
|
|
|
pub c_time: String,
|
|
|
pub ccy: String,
|
|
|
@@ -192,52 +192,51 @@ pub struct SwapPosition {
|
|
|
pub imr: String,
|
|
|
pub inst_id: String,
|
|
|
pub inst_type: String,
|
|
|
- pub interest: Decimal,
|
|
|
- pub idx_px: Decimal,
|
|
|
- pub last: Decimal,
|
|
|
+ pub interest: String,
|
|
|
+ pub idx_px: String,
|
|
|
+ pub last: String,
|
|
|
pub usd_px: String,
|
|
|
- pub be_px: Decimal,
|
|
|
+ pub be_px: String,
|
|
|
pub lever: Decimal,
|
|
|
pub liab: String,
|
|
|
pub liab_ccy: String,
|
|
|
- pub liq_px: Decimal,
|
|
|
- pub mark_px: Decimal,
|
|
|
- pub margin: Decimal,
|
|
|
- pub mgn_mode: Decimal,
|
|
|
- pub mgn_ratio: Decimal,
|
|
|
- pub mmr: Decimal,
|
|
|
- pub notional_usd: Decimal,
|
|
|
+ pub liq_px: String,
|
|
|
+ pub mark_px: String,
|
|
|
+ pub margin: String,
|
|
|
+ pub mgn_mode: String,
|
|
|
+ pub mgn_ratio: String,
|
|
|
+ pub mmr: String,
|
|
|
+ pub notional_usd: String,
|
|
|
pub opt_val: String,
|
|
|
- pub p_time: String,
|
|
|
pub pos: Decimal,
|
|
|
pub pos_ccy: String,
|
|
|
- pub pos_id: Decimal,
|
|
|
+ pub pos_id: String,
|
|
|
pub pos_side: String,
|
|
|
pub spot_in_use_amt: String,
|
|
|
pub spot_in_use_ccy: String,
|
|
|
pub theta_b_s: String,
|
|
|
pub theta_p_a: String,
|
|
|
- pub trade_id: Decimal,
|
|
|
+ pub trade_id: String,
|
|
|
pub biz_ref_id: String,
|
|
|
pub biz_ref_type: String,
|
|
|
- pub quote_bal: Decimal,
|
|
|
- pub base_bal: Decimal,
|
|
|
+ pub quote_bal: String,
|
|
|
+ pub base_bal: String,
|
|
|
pub base_borrowed: String,
|
|
|
pub base_interest: String,
|
|
|
pub quote_borrowed: String,
|
|
|
pub quote_interest: String,
|
|
|
pub u_time: String,
|
|
|
pub upl: Decimal,
|
|
|
- pub upl_last_px: Decimal,
|
|
|
- pub upl_ratio: Decimal,
|
|
|
- pub upl_ratio_last_px: Decimal,
|
|
|
+ pub upl_last_px: String,
|
|
|
+ pub upl_ratio: String,
|
|
|
+ pub upl_ratio_last_px: String,
|
|
|
pub vega_b_s: String,
|
|
|
pub vega_p_a: String,
|
|
|
- pub realized_pnl: Decimal,
|
|
|
- pub pnl: Decimal,
|
|
|
- pub fee: Decimal,
|
|
|
- pub funding_fee: Decimal,
|
|
|
- pub liq_penalty: Decimal,
|
|
|
+ pub realized_pnl: String,
|
|
|
+ pub pnl: String,
|
|
|
+ pub fee: String,
|
|
|
+ pub funding_fee: String,
|
|
|
+ pub liq_penalty: String,
|
|
|
pub close_order_algo: Vec<SwapPositionCloseOrderAlgo>,
|
|
|
}
|
|
|
|
|
|
@@ -245,15 +244,15 @@ pub struct SwapPosition {
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
pub struct SwapPositionCloseOrderAlgo {
|
|
|
pub algo_id: String,
|
|
|
- pub sl_trigger_px: Decimal,
|
|
|
+ pub sl_trigger_px: String,
|
|
|
pub sl_trigger_px_type: String,
|
|
|
- pub tp_trigger_px: Decimal,
|
|
|
+ pub tp_trigger_px: String,
|
|
|
pub tp_trigger_px_type: String,
|
|
|
- pub close_fraction: Decimal,
|
|
|
+ pub close_fraction: String,
|
|
|
}
|
|
|
|
|
|
-/// Kucoin交易所行情信息请求数据结构
|
|
|
-/// - 接口`"/api/v1/ticker"`
|
|
|
+/// Okx交易所行情信息请求数据结构
|
|
|
+/// - 接口`"/api/v5/market/ticker"`
|
|
|
///
|
|
|
/// struct SwapTicker
|
|
|
/// - `inst_type`: String, 产品类型
|
|
|
@@ -293,6 +292,176 @@ struct SwapTicker {
|
|
|
sod_utc8: Decimal,
|
|
|
}
|
|
|
|
|
|
+/// Okx交易所市场信息请求数据结构
|
|
|
+/// - 接口`"/api/v5/public/instruments"`
|
|
|
+///
|
|
|
+/// struct SwapMarket
|
|
|
+/// - `alias`: String,
|
|
|
+/// - `base_ccy`: String,
|
|
|
+/// - `category`: String,
|
|
|
+/// - `ct_mult`: Decimal,
|
|
|
+/// - `ct_type`: String,
|
|
|
+/// - `ct_val`: Decimal,
|
|
|
+/// - `ct_val_ccy`: String,
|
|
|
+/// - `exp_time`: String,
|
|
|
+/// - `inst_family`: String,
|
|
|
+/// - `inst_id`: String,
|
|
|
+/// - `inst_type`: String,
|
|
|
+/// - `lever`: Decimal,
|
|
|
+/// - `list_time`: String,
|
|
|
+/// - `lot_sz`: Decimal,
|
|
|
+/// - `max_iceberg_sz`: Decimal,
|
|
|
+/// - `max_lmt_sz`: Decimal,
|
|
|
+/// - `max_mkt_sz`: Decimal,
|
|
|
+/// - `max_stop_sz`: Decimal,
|
|
|
+/// - `max_trigger_sz`: Decimal,
|
|
|
+/// - `max_twap_sz`: Decimal,
|
|
|
+/// - `min_sz`: Decimal,
|
|
|
+/// - `opt_type`: String,
|
|
|
+/// - `quote_ccy`: String,
|
|
|
+/// - `settle_ccy`: String,
|
|
|
+/// - `state`: String,
|
|
|
+/// - `stk`: String,
|
|
|
+/// - `tick_sz`: Decimal,
|
|
|
+/// - `uly`: String,
|
|
|
+#[derive(Debug, Clone, Deserialize, Serialize)]
|
|
|
+#[serde(rename_all = "camelCase")]
|
|
|
+struct SwapMarket {
|
|
|
+ alias: String,
|
|
|
+ base_ccy: String,
|
|
|
+ category: String,
|
|
|
+ ct_mult: Decimal,
|
|
|
+ ct_type: String,
|
|
|
+ ct_val: Decimal,
|
|
|
+ ct_val_ccy: String,
|
|
|
+ exp_time: String,
|
|
|
+ inst_family: String,
|
|
|
+ inst_id: String,
|
|
|
+ inst_type: String,
|
|
|
+ lever: Decimal,
|
|
|
+ list_time: String,
|
|
|
+ lot_sz: Decimal,
|
|
|
+ max_iceberg_sz: Decimal,
|
|
|
+ max_lmt_sz: Decimal,
|
|
|
+ max_mkt_sz: Decimal,
|
|
|
+ max_stop_sz: Decimal,
|
|
|
+ max_trigger_sz: Decimal,
|
|
|
+ max_twap_sz: Decimal,
|
|
|
+ min_sz: Decimal,
|
|
|
+ opt_type: String,
|
|
|
+ quote_ccy: String,
|
|
|
+ settle_ccy: String,
|
|
|
+ state: String,
|
|
|
+ stk: String,
|
|
|
+ tick_sz: Decimal,
|
|
|
+ uly: String,
|
|
|
+}
|
|
|
+
|
|
|
+/// Okx交易所订单信息请求数据结构
|
|
|
+/// - 接口`"/api/v5/trade/order"`
|
|
|
+///
|
|
|
+/// struct SwapOrder
|
|
|
+/// - `inst_type`: String, 产品类型
|
|
|
+/// - `inst_id`: String, 产品ID
|
|
|
+/// - `ccy`: String, 保证金币种
|
|
|
+/// - `ord_id`: String, 订单ID
|
|
|
+/// - `cl_ord_id`: String, 客户自定义订单ID
|
|
|
+/// - `tag`: String, 订单标签
|
|
|
+/// - `px`: Decimal, 委托价格
|
|
|
+/// - `px_usd`: String, 期权价格
|
|
|
+/// - `px_vol`: String, 期权订单的隐含波动率
|
|
|
+/// - `px_type`: String, 期权的价格类型
|
|
|
+/// - `sz`: Decimal, 委托数量
|
|
|
+/// - `pnl`: Decimal, 收益
|
|
|
+/// - `ord_type`: String, 订单类型
|
|
|
+/// - `side`: String, 订单方向
|
|
|
+/// - `pos_side`: String, 持仓方向
|
|
|
+/// - `td_mode`: String, 交易模式
|
|
|
+/// - `acc_fill_sz`: Decimal, 累计成交数量
|
|
|
+/// - `fill_px`: String, 最新成交价格,如果成交数量为0,该字段为""
|
|
|
+/// - `trade_id`: String, 最新成交ID
|
|
|
+/// - `fill_sz`: Decimal, 最新成交数量
|
|
|
+/// - `fill_time`: String, 最新成交时间
|
|
|
+/// - `source`: String, 订单来源
|
|
|
+/// - `state`: String, 订单状态
|
|
|
+/// - `avg_px`: Decimal, 成交均价,如果成交数量为0,该字段也为""
|
|
|
+/// - `lever`: Decimal, 杠杆倍数
|
|
|
+/// - `attach_algo_cl_ord_id`: String, 下单附带止盈止损时,客户自定义的策略订单ID
|
|
|
+/// - `tp_trigger_px`: Decimal, 止盈触发价
|
|
|
+/// - `tp_trigger_px_type`: String, 止盈触发价类型
|
|
|
+/// - `tp_ord_px`: Decimal, 止盈委托价
|
|
|
+/// - `sl_trigger_px`: Decimal, 止损触发价
|
|
|
+/// - `sl_trigger_px_type`: String, 止损触发价类型
|
|
|
+/// - `sl_ord_px`: Decimal, 止损委托价
|
|
|
+/// - `stp_id`: String, 自成交保护ID
|
|
|
+/// - `stp_mode`: String, 自成交保护模式
|
|
|
+/// - `fee_ccy`: String, 交易手续费币种
|
|
|
+/// - `fee`: Decimal, 手续费与返佣
|
|
|
+/// - `rebate_ccy`: String, 返佣金币种
|
|
|
+/// - `rebate`: String, 返佣金额,仅适用于币币和杠杆
|
|
|
+/// - `tgt_ccy`: String, 币币市价单委托数量sz的单位
|
|
|
+/// - `category`: String, 订单种类
|
|
|
+/// - `reduce_only`: String, 是否只减仓
|
|
|
+/// - `cancel_source`: String, 订单取消来源的原因枚举值代码
|
|
|
+/// - `cancel_source_reason`: String, 订单取消来源的对应具体原因
|
|
|
+/// - `quick_mgn_type`: String, 一键借币类型,仅适用于杠杆逐仓的一键借币模式
|
|
|
+/// - `algo_cl_ord_id`: String, 客户自定义策略订单ID
|
|
|
+/// - `algo_id`: String, 策略委托单ID,策略订单触发时有值,否则为""
|
|
|
+/// - `u_time`: String, 订单状态更新时间
|
|
|
+/// - `c_time`: String, 订单创建时间
|
|
|
+#[derive(Debug, Clone, Deserialize, Serialize)]
|
|
|
+#[serde(rename_all = "camelCase")]
|
|
|
+pub struct SwapOrder {
|
|
|
+ inst_type: String,
|
|
|
+ inst_id: String,
|
|
|
+ ccy: String,
|
|
|
+ ord_id: String,
|
|
|
+ cl_ord_id: String,
|
|
|
+ tag: String,
|
|
|
+ px: Decimal,
|
|
|
+ px_usd: String,
|
|
|
+ px_vol: String,
|
|
|
+ px_type: String,
|
|
|
+ sz: Decimal,
|
|
|
+ pnl: String,
|
|
|
+ ord_type: String,
|
|
|
+ side: String,
|
|
|
+ pos_side: String,
|
|
|
+ td_mode: String,
|
|
|
+ acc_fill_sz: Decimal,
|
|
|
+ fill_px: String,
|
|
|
+ trade_id: String,
|
|
|
+ fill_sz: String,
|
|
|
+ fill_time: String,
|
|
|
+ source: String,
|
|
|
+ state: String,
|
|
|
+ avg_px: String,
|
|
|
+ lever: String,
|
|
|
+ attach_algo_cl_ord_id: String,
|
|
|
+ tp_trigger_px: String,
|
|
|
+ tp_trigger_px_type: String,
|
|
|
+ tp_ord_px: String,
|
|
|
+ sl_trigger_px: String,
|
|
|
+ sl_trigger_px_type: String,
|
|
|
+ sl_ord_px: String,
|
|
|
+ stp_id: String,
|
|
|
+ stp_mode: String,
|
|
|
+ fee_ccy: String,
|
|
|
+ fee: String,
|
|
|
+ rebate_ccy: String,
|
|
|
+ rebate: String,
|
|
|
+ tgt_ccy: String,
|
|
|
+ category: String,
|
|
|
+ reduce_only: String,
|
|
|
+ cancel_source: String,
|
|
|
+ cancel_source_reason: String,
|
|
|
+ quick_mgn_type: String,
|
|
|
+ algo_cl_ord_id: String,
|
|
|
+ algo_id: String,
|
|
|
+ u_time: String,
|
|
|
+ c_time: String,
|
|
|
+}
|
|
|
+
|
|
|
#[allow(dead_code)]
|
|
|
#[derive(Clone)]
|
|
|
pub struct OkxSwap {
|
|
|
@@ -363,23 +532,24 @@ impl Platform for OkxSwap {
|
|
|
let res_data_str = &res_data.data;
|
|
|
let balance_info_list: Vec<SwapAccount> = serde_json::from_str(res_data_str).unwrap();
|
|
|
let detail = balance_info_list[0].details.iter().find(|&item| item.ccy == symbol_array[1]);
|
|
|
- let balance_info: SwapAccountDetails = match detail {
|
|
|
+ match detail {
|
|
|
None => {
|
|
|
error!("Okx:获取Account信息错误!\nhandle_swap_account:res_data={:?}", res_data);
|
|
|
panic!("Okx:获取Account信息错误!\nhandle_swap_account:res_data={:?}", res_data)
|
|
|
}
|
|
|
- Some(value) => { value.clone() }
|
|
|
- };
|
|
|
- let result = Account {
|
|
|
- coin: balance_info.ccy.to_uppercase(),
|
|
|
- balance: balance_info.avail_bal + balance_info.fixed_bal,
|
|
|
- available_balance: balance_info.avail_bal,
|
|
|
- frozen_balance: balance_info.fixed_bal,
|
|
|
- stocks: Decimal::ZERO,
|
|
|
- available_stocks: Decimal::ZERO,
|
|
|
- frozen_stocks: Decimal::ZERO,
|
|
|
- };
|
|
|
- Ok(result)
|
|
|
+ Some(value) => {
|
|
|
+ let result = Account {
|
|
|
+ coin: value.ccy.to_uppercase(),
|
|
|
+ balance: value.avail_bal + value.fixed_bal,
|
|
|
+ available_balance: value.avail_bal,
|
|
|
+ frozen_balance: value.fixed_bal,
|
|
|
+ stocks: Decimal::ZERO,
|
|
|
+ available_stocks: Decimal::ZERO,
|
|
|
+ frozen_stocks: Decimal::ZERO,
|
|
|
+ };
|
|
|
+ Ok(result)
|
|
|
+ }
|
|
|
+ }
|
|
|
} else {
|
|
|
Err(Error::new(ErrorKind::Other, res_data.to_string()))
|
|
|
}
|
|
|
@@ -390,23 +560,15 @@ impl Platform for OkxSwap {
|
|
|
}
|
|
|
|
|
|
async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
|
|
|
- let symbol_format = utils::format_symbol(self.symbol.to_string(), "-");
|
|
|
+ let symbol_format = format!("{}-SWAP", utils::format_symbol(self.symbol.to_string(), "-"));
|
|
|
let ct_val = self.market.ct_val;
|
|
|
let res_data = self.request.get_positions("SWAP".to_string()).await;
|
|
|
if res_data.code == "200" {
|
|
|
let res_data_str = &res_data.data;
|
|
|
let data_list: Vec<SwapPosition> = serde_json::from_str(&res_data_str).unwrap();
|
|
|
- let position_info = data_list.iter().find(|&item| item.inst_id == format!("{}-SWAP", symbol_format));
|
|
|
- match position_info {
|
|
|
- None => {
|
|
|
- error!("okx_swap:获取Position信息错误!\nget_position:res_data={:?}", res_data_str);
|
|
|
- panic!("okx_swap:获取Position信息错误!\nget_position:res_data={:?}", res_data_str)
|
|
|
- }
|
|
|
- Some(value) => {
|
|
|
- let result = okx_handle::format_position_item(value, ct_val);
|
|
|
- Ok(vec![result])
|
|
|
- }
|
|
|
- }
|
|
|
+ let position_info: Vec<&SwapPosition> = data_list.iter().filter(|item| item.inst_id == symbol_format).collect();
|
|
|
+ let result = position_info.iter().map(|item| okx_handle::format_position_item(item, ct_val)).collect();
|
|
|
+ Ok(result)
|
|
|
} else {
|
|
|
Err(Error::new(ErrorKind::Other, res_data.to_string()))
|
|
|
}
|
|
|
@@ -425,12 +587,12 @@ impl Platform for OkxSwap {
|
|
|
}
|
|
|
|
|
|
async fn get_ticker(&mut self) -> Result<Ticker, Error> {
|
|
|
- let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
|
|
|
+ let symbol_format = format!("{}-SWAP", utils::format_symbol(self.symbol.clone(), "-"));
|
|
|
let res_data = self.request.get_ticker(symbol_format.clone()).await;
|
|
|
if res_data.code == "200" {
|
|
|
let res_data_str = &res_data.data;
|
|
|
let ticker_info_list: Vec<SwapTicker> = serde_json::from_str(&res_data_str).unwrap();
|
|
|
- let ticker_info = ticker_info_list.iter().find(|item| item.inst_id == format!("{}-SWAP", symbol_format.clone()));
|
|
|
+ let ticker_info = ticker_info_list.iter().find(|item| item.inst_id == symbol_format);
|
|
|
match ticker_info {
|
|
|
None => {
|
|
|
error!("okx_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data_str);
|
|
|
@@ -455,12 +617,12 @@ impl Platform for OkxSwap {
|
|
|
}
|
|
|
|
|
|
async fn get_ticker_symbol(&mut self, symbol: String) -> Result<Ticker, Error> {
|
|
|
- let symbol_format = utils::format_symbol(symbol.clone(), "-");
|
|
|
+ let symbol_format = format!("{}-SWAP", utils::format_symbol(symbol.clone(), "-"));
|
|
|
let res_data = self.request.get_ticker(symbol_format.clone()).await;
|
|
|
if res_data.code == "200" {
|
|
|
let res_data_str = &res_data.data;
|
|
|
let ticker_info_list: Vec<SwapTicker> = serde_json::from_str(&res_data_str).unwrap();
|
|
|
- let ticker_info = ticker_info_list.iter().find(|item| item.inst_id == format!("{}-SWAP", symbol_format.clone()));
|
|
|
+ let ticker_info = ticker_info_list.iter().find(|item| item.inst_id == symbol_format);
|
|
|
match ticker_info {
|
|
|
None => {
|
|
|
error!("okx_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data_str);
|
|
|
@@ -489,41 +651,29 @@ impl Platform for OkxSwap {
|
|
|
let res_data = self.request.get_instruments().await;
|
|
|
if res_data.code == "200" {
|
|
|
let res_data_str = &res_data.data;
|
|
|
- let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
|
|
|
- let market_info = res_data_json.iter().find(|item| item["instId"].as_str().unwrap() == format!("{}-SWAP", symbol_format));
|
|
|
+ let res_data_json: Vec<SwapMarket> = serde_json::from_str(res_data_str).unwrap();
|
|
|
+ let market_info = res_data_json.iter().find(|item| item.inst_id == format!("{}-SWAP", symbol_format));
|
|
|
match market_info {
|
|
|
None => {
|
|
|
error!("okx_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data_str);
|
|
|
panic!("okx_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data_str)
|
|
|
}
|
|
|
Some(value) => {
|
|
|
- let base_asset = value["ctValCcy"].as_str().unwrap_or("").to_string();
|
|
|
- let quote_asset = value["settleCcy"].as_str().unwrap_or("").to_string();
|
|
|
- let tick_size = Decimal::from_str(&value["tickSz"].as_str().unwrap()).unwrap();
|
|
|
- let min_qty = Decimal::from_str(&value["minSz"].as_str().unwrap()).unwrap();
|
|
|
- let max_qty = Decimal::from_str(&value["maxLmtSz"].as_str().unwrap()).unwrap();
|
|
|
- let ct_val = Decimal::from_str(&value["ctVal"].as_str().unwrap()).unwrap();
|
|
|
-
|
|
|
-
|
|
|
- let amount_size = min_qty * ct_val;
|
|
|
- let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
|
|
|
- let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
|
|
|
- let min_notional = min_qty * ct_val;
|
|
|
- let max_notional = max_qty * ct_val;
|
|
|
-
|
|
|
+ println!("{:?}", value);
|
|
|
+ let symbol_array: Vec<&str> = value.inst_family.split("-").collect();
|
|
|
let result = Market {
|
|
|
- symbol: format!("{}_{}", base_asset, quote_asset),
|
|
|
- base_asset,
|
|
|
- quote_asset,
|
|
|
- tick_size,
|
|
|
- amount_size,
|
|
|
- price_precision,
|
|
|
- amount_precision,
|
|
|
- min_qty,
|
|
|
- max_qty,
|
|
|
- min_notional,
|
|
|
- max_notional,
|
|
|
- ct_val,
|
|
|
+ symbol: format!("{}_{}", symbol_array[0], symbol_array[1]),
|
|
|
+ base_asset: symbol_array[0].to_string(),
|
|
|
+ quote_asset: symbol_array[1].to_string(),
|
|
|
+ tick_size: value.tick_sz,
|
|
|
+ amount_size: value.min_sz * value.ct_val,
|
|
|
+ price_precision: Decimal::from_u32(value.tick_sz.scale()).unwrap(),
|
|
|
+ amount_precision: Decimal::from_u32((value.min_sz * value.ct_val).scale()).unwrap(),
|
|
|
+ min_qty: value.min_sz,
|
|
|
+ max_qty: value.max_lmt_sz,
|
|
|
+ min_notional: value.min_sz * value.ct_val,
|
|
|
+ max_notional: value.max_lmt_sz * value.ct_val,
|
|
|
+ ct_val: value.ct_val,
|
|
|
};
|
|
|
Ok(result)
|
|
|
}
|
|
|
@@ -538,41 +688,28 @@ impl Platform for OkxSwap {
|
|
|
let res_data = self.request.get_instruments().await;
|
|
|
if res_data.code == "200" {
|
|
|
let res_data_str = &res_data.data;
|
|
|
- let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
|
|
|
- let market_info = res_data_json.iter().find(|item| item["instId"].as_str().unwrap() == format!("{}-SWAP", symbol_format));
|
|
|
+ let res_data_json: Vec<SwapMarket> = serde_json::from_str(res_data_str).unwrap();
|
|
|
+ let market_info = res_data_json.iter().find(|item| item.inst_id == format!("{}-SWAP", symbol_format));
|
|
|
match market_info {
|
|
|
None => {
|
|
|
error!("okx_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data_str);
|
|
|
panic!("okx_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data_str)
|
|
|
}
|
|
|
Some(value) => {
|
|
|
- let base_asset = value["ctValCcy"].as_str().unwrap_or("").to_string();
|
|
|
- let quote_asset = value["settleCcy"].as_str().unwrap_or("").to_string();
|
|
|
- let tick_size = Decimal::from_str(&value["tickSz"].as_str().unwrap()).unwrap();
|
|
|
- let min_qty = Decimal::from_str(&value["minSz"].as_str().unwrap()).unwrap();
|
|
|
- let max_qty = Decimal::from_str(&value["maxLmtSz"].as_str().unwrap()).unwrap();
|
|
|
- let ct_val = Decimal::from_str(&value["ctVal"].as_str().unwrap()).unwrap();
|
|
|
-
|
|
|
-
|
|
|
- let amount_size = min_qty * ct_val;
|
|
|
- let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
|
|
|
- let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
|
|
|
- let min_notional = min_qty * ct_val;
|
|
|
- let max_notional = max_qty * ct_val;
|
|
|
-
|
|
|
+ let symbol_array: Vec<&str> = value.inst_family.split("-").collect();
|
|
|
let result = Market {
|
|
|
- symbol: format!("{}_{}", base_asset, quote_asset),
|
|
|
- base_asset,
|
|
|
- quote_asset,
|
|
|
- tick_size,
|
|
|
- amount_size,
|
|
|
- price_precision,
|
|
|
- amount_precision,
|
|
|
- min_qty,
|
|
|
- max_qty,
|
|
|
- min_notional,
|
|
|
- max_notional,
|
|
|
- ct_val,
|
|
|
+ symbol: format!("{}_{}", symbol_array[0], symbol_array[1]),
|
|
|
+ base_asset: symbol_array[0].to_string(),
|
|
|
+ quote_asset: symbol_array[1].to_string(),
|
|
|
+ tick_size: value.tick_sz,
|
|
|
+ amount_size: value.min_sz * value.ct_val,
|
|
|
+ price_precision: Decimal::from_u32(value.tick_sz.scale()).unwrap(),
|
|
|
+ amount_precision: Decimal::from_u32((value.min_sz * value.ct_val).scale()).unwrap(),
|
|
|
+ min_qty: value.min_sz,
|
|
|
+ max_qty: value.max_lmt_sz,
|
|
|
+ min_notional: value.min_sz * value.ct_val,
|
|
|
+ max_notional: value.max_lmt_sz * value.ct_val,
|
|
|
+ ct_val: value.ct_mult,
|
|
|
};
|
|
|
Ok(result)
|
|
|
}
|
|
|
@@ -583,13 +720,14 @@ impl Platform for OkxSwap {
|
|
|
}
|
|
|
|
|
|
async fn get_order_detail(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
|
|
|
+ let symbol_format = format!("{}-SWAP", utils::format_symbol(self.symbol.clone(), "-"));
|
|
|
let ct_val = self.market.ct_val;
|
|
|
- let res_data = self.request.get_order(self.symbol.clone(), order_id.to_string(), custom_id.to_string()).await;
|
|
|
+ let res_data = self.request.get_order(symbol_format, order_id.to_string(), custom_id.to_string()).await;
|
|
|
if res_data.code == "200" {
|
|
|
let res_data_str = &res_data.data;
|
|
|
- let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
|
|
|
+ let res_data_json: Vec<SwapOrder> = serde_json::from_str(res_data_str).unwrap();
|
|
|
let order_info = res_data_json[0].clone();
|
|
|
- let result = okx_handle::format_order_item(order_info, ct_val);
|
|
|
+ let result = format_order_item(order_info, ct_val);
|
|
|
Ok(result)
|
|
|
} else {
|
|
|
Err(Error::new(ErrorKind::Other, res_data.to_string()))
|
|
|
@@ -597,13 +735,14 @@ impl Platform for OkxSwap {
|
|
|
}
|
|
|
|
|
|
async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
|
|
|
- let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
|
|
|
+ let symbol_format = format!("{}-SWAP", utils::format_symbol(self.symbol.clone(), "-"));
|
|
|
let ct_val = self.market.ct_val;
|
|
|
let res_data = self.request.get_incomplete_order(symbol_format.clone()).await;
|
|
|
if res_data.code == "200" {
|
|
|
let res_data_str = &res_data.data;
|
|
|
- let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
|
|
|
- let result = res_data_json.iter().map(|item| okx_handle::format_order_item(item.clone(), ct_val)).collect();
|
|
|
+ println!("{}", res_data_str);
|
|
|
+ let res_data_json: Vec<SwapOrder> = serde_json::from_str(res_data_str).unwrap();
|
|
|
+ let result = res_data_json.iter().map(|item| format_order_item(item.clone(), ct_val)).collect();
|
|
|
Ok(result)
|
|
|
} else {
|
|
|
Err(Error::new(ErrorKind::Other, res_data.to_string()))
|
|
|
@@ -611,7 +750,7 @@ impl Platform for OkxSwap {
|
|
|
}
|
|
|
|
|
|
async fn take_order(&mut self, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
|
|
|
- let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
|
|
|
+ let symbol_format = format!("{}-SWAP", utils::format_symbol(self.symbol.clone(), "-"));
|
|
|
let ct_val = self.market.ct_val;
|
|
|
let mut params = json!({
|
|
|
"tdMode": "cross",
|
|
|
@@ -625,23 +764,40 @@ impl Platform for OkxSwap {
|
|
|
match origin_side {
|
|
|
"kd" => {
|
|
|
params["side"] = json!("buy");
|
|
|
+ params["posSide"] = json!("long");
|
|
|
}
|
|
|
"pd" => {
|
|
|
params["side"] = json!("sell");
|
|
|
+ params["posSide"] = json!("long");
|
|
|
}
|
|
|
"kk" => {
|
|
|
params["side"] = json!("sell");
|
|
|
+ params["posSide"] = json!("short");
|
|
|
}
|
|
|
"pk" => {
|
|
|
params["side"] = json!("buy");
|
|
|
+ params["posSide"] = json!("short");
|
|
|
}
|
|
|
_ => { error!("下单参数错误"); }
|
|
|
};
|
|
|
let res_data = self.request.swap_order(params).await;
|
|
|
if res_data.code == "200" {
|
|
|
let res_data_str = &res_data.data;
|
|
|
- let res_data_json: serde_json::Value = serde_json::from_str(res_data_str).unwrap();
|
|
|
- let result = okx_handle::format_order_item(res_data_json, ct_val);
|
|
|
+ let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
|
|
|
+ let order_info = res_data_json[0].clone();
|
|
|
+ let id = order_info["ordId"].as_str().unwrap().to_string();
|
|
|
+ let custom_id = order_info["clOrdId"].as_str().unwrap().to_string();
|
|
|
+ let result = Order {
|
|
|
+ id,
|
|
|
+ custom_id,
|
|
|
+ price,
|
|
|
+ amount,
|
|
|
+ deal_amount: Decimal::ZERO,
|
|
|
+ avg_price: Decimal::ZERO,
|
|
|
+ status: "NEW".to_string(),
|
|
|
+ order_type: "".to_string(),
|
|
|
+ trace_stack: TraceStack::default().on_special("798 okx_swap".to_string()),
|
|
|
+ };
|
|
|
Ok(result)
|
|
|
} else {
|
|
|
Err(Error::new(ErrorKind::Other, res_data.to_string()))
|
|
|
@@ -649,7 +805,7 @@ impl Platform for OkxSwap {
|
|
|
}
|
|
|
|
|
|
async fn take_order_symbol(&mut self, symbol: String, ct_val: Decimal, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
|
|
|
- let symbol_format = utils::format_symbol(symbol.clone(), "-");
|
|
|
+ let symbol_format = format!("{}-SWAP", utils::format_symbol(symbol.clone(), "-"));
|
|
|
let mut params = json!({
|
|
|
"tdMode": "cross",
|
|
|
"clOrdId": custom_id.to_string(),
|
|
|
@@ -662,23 +818,40 @@ impl Platform for OkxSwap {
|
|
|
match origin_side {
|
|
|
"kd" => {
|
|
|
params["side"] = json!("buy");
|
|
|
+ params["posSide"] = json!("long");
|
|
|
}
|
|
|
"pd" => {
|
|
|
params["side"] = json!("sell");
|
|
|
+ params["posSide"] = json!("long");
|
|
|
}
|
|
|
"kk" => {
|
|
|
params["side"] = json!("sell");
|
|
|
+ params["posSide"] = json!("short");
|
|
|
}
|
|
|
"pk" => {
|
|
|
params["side"] = json!("buy");
|
|
|
+ params["posSide"] = json!("short");
|
|
|
}
|
|
|
_ => { error!("下单参数错误"); }
|
|
|
};
|
|
|
let res_data = self.request.swap_order(params).await;
|
|
|
if res_data.code == "200" {
|
|
|
let res_data_str = &res_data.data;
|
|
|
- let res_data_json: serde_json::Value = serde_json::from_str(res_data_str).unwrap();
|
|
|
- let result = okx_handle::format_order_item(res_data_json, ct_val);
|
|
|
+ let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
|
|
|
+ let order_info = res_data_json[0].clone();
|
|
|
+ let id = order_info["ordId"].as_str().unwrap().to_string();
|
|
|
+ let custom_id = order_info["clOrdId"].as_str().unwrap().to_string();
|
|
|
+ let result = Order {
|
|
|
+ id,
|
|
|
+ custom_id,
|
|
|
+ price,
|
|
|
+ amount,
|
|
|
+ deal_amount: Decimal::ZERO,
|
|
|
+ avg_price: Decimal::ZERO,
|
|
|
+ status: "NEW".to_string(),
|
|
|
+ order_type: "".to_string(),
|
|
|
+ trace_stack: TraceStack::default().on_special("852 okx_swap".to_string()),
|
|
|
+ };
|
|
|
Ok(result)
|
|
|
} else {
|
|
|
Err(Error::new(ErrorKind::Other, res_data.to_string()))
|
|
|
@@ -686,12 +859,8 @@ impl Platform for OkxSwap {
|
|
|
}
|
|
|
|
|
|
async fn cancel_order(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
|
|
|
- let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
|
|
|
+ let symbol_format = format!("{}-SWAP", utils::format_symbol(self.symbol.clone(), "-"));
|
|
|
let res_data = self.request.cancel_order(symbol_format, order_id.to_string(), custom_id.to_string()).await;
|
|
|
- if order_id == "" {
|
|
|
- error!("okx_swap:撤销订单错误,该交易所为提供自定义订单号撤销订单!\ncancel_order:order_id={:?},custom_id={:?}", order_id, custom_id);
|
|
|
- panic!("okx_swap:撤销订单错误,该交易所为提供自定义订单号撤销订单!\ncancel_order:order_id={:?},custom_id={:?}", order_id, custom_id)
|
|
|
- }
|
|
|
if res_data.code == "200" {
|
|
|
let res_data_str = &res_data.data;
|
|
|
let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
|
|
|
@@ -707,7 +876,7 @@ impl Platform for OkxSwap {
|
|
|
avg_price: Decimal::ZERO,
|
|
|
status: "REMOVE".to_string(),
|
|
|
order_type: "".to_string(),
|
|
|
- trace_stack: TraceStack::default().on_special("428 okx_handle".to_string()),
|
|
|
+ trace_stack: TraceStack::default().on_special("854 okx_swap".to_string()),
|
|
|
};
|
|
|
Ok(result)
|
|
|
} else {
|
|
|
@@ -735,7 +904,7 @@ impl Platform for OkxSwap {
|
|
|
}
|
|
|
|
|
|
async fn set_dual_leverage(&mut self, leverage: &str) -> Result<String, Error> {
|
|
|
- let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
|
|
|
+ let symbol_format = format!("{}-SWAP", utils::format_symbol(self.symbol.clone(), "-"));
|
|
|
let res_data = self.request.set_leverage(symbol_format, leverage.to_string()).await;
|
|
|
if res_data.code == "200" {
|
|
|
let res_data_str = &res_data.data;
|
|
|
@@ -857,3 +1026,24 @@ impl Platform for OkxSwap {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+pub fn format_order_item(data: SwapOrder, ct_val: Decimal) -> Order {
|
|
|
+ let custom_status = if ["canceled", "filled", "mmp_canceled"].contains(&data.state.as_str()) {
|
|
|
+ "REMOVE".to_string()
|
|
|
+ } else if ["live", "partially_filled"].contains(&data.state.as_str()) {
|
|
|
+ "NEW".to_string()
|
|
|
+ } else {
|
|
|
+ "NULL".to_string()
|
|
|
+ };
|
|
|
+
|
|
|
+ Order {
|
|
|
+ id: data.ord_id,
|
|
|
+ custom_id: data.cl_ord_id,
|
|
|
+ price: data.px,
|
|
|
+ amount: data.sz * ct_val,
|
|
|
+ deal_amount: data.acc_fill_sz * ct_val,
|
|
|
+ avg_price: if data.avg_px != "" { Decimal::from_str(&data.avg_px).unwrap() } else { Decimal::ZERO },
|
|
|
+ status: custom_status,
|
|
|
+ order_type: data.ord_type,
|
|
|
+ trace_stack: TraceStack::default().on_special("1022 okx_swap".to_string()),
|
|
|
+ }
|
|
|
+}
|