tradingbot/src/future/mod.rs
2024-05-20 22:05:07 +09:00

222 lines
6.1 KiB
Rust

pub mod order;
pub mod table_mgmt;
use hmac_sha256::HMAC;
use crate::RunningMode::*;
use crate::{API_KEY, API_KEY_TESTNET, RUNNING_MODE, SECRET_KEY, SECRET_KEY_TESTNET, FUTURES_URL, FUTURES_URL_TEST};
use crate::strategy_team::{AllData, TimeData};
use crate::database_control::*;
use rust_decimal::Decimal;
use sqlx::FromRow;
use hex::ToHex;
use crate::future::table_mgmt::select_listuped_positions;
#[derive(Debug, PartialEq, Clone, sqlx::Type)]
pub enum Position {
Long,
Short
}
#[derive(Debug, PartialEq, Clone, sqlx::Type)]
pub enum Status {
#[sqlx(rename = "listup")]
Listup,
#[sqlx(rename = "filled")]
Filled,
#[sqlx(rename = "partially_filled")]
PartiallyFilled
}
impl std::fmt::Display for Position {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
pub struct EntryCoinInfo {
pub symbol: String,
pub close_time: i64,
pub registered_server_epoch: i64,
}
impl EntryCoinInfo {
fn new() -> EntryCoinInfo {
let a = EntryCoinInfo {
symbol: String::new(),
close_time: 0,
registered_server_epoch: 0
};
a
}
}
#[derive(Debug, Clone)]
pub enum ContractType {
Perpetual, // this is the target
CurrentMonth,
NextMonth,
CurrentQuarter,
NextQuarter,
PerpetualDelivering,
}
#[derive(Debug, Clone)]
pub enum ContractStatus {
PendingTrading, // this is the target
Trading,
PreDelivering,
Delivering,
Delivered,
PreSettle,
Settling,
Close,
}
#[derive(Debug, FromRow, Clone)]
pub struct FuturesExchangeInfo {
pub stepsize: Decimal,
pub ticksize: Decimal,
pub contract_type: ContractType,
pub contract_status: ContractStatus,
pub base_asset_precision: u32,
pub quote_precision: u32,
pub notional: Decimal
}
impl FuturesExchangeInfo {
fn new() -> FuturesExchangeInfo {
let a = FuturesExchangeInfo {
stepsize: Decimal::new(0, 8),
ticksize: Decimal::new(0, 8),
contract_type: ContractType::Perpetual,
contract_status: ContractStatus::Trading,
base_asset_precision: 0,
quote_precision: 0,
notional: Decimal::new(0, 8),
};
a
}
}
#[derive(Clone, Debug)]
pub struct FuturesTradeFee {
user_level: Option<i32>,
taker_fee_percent: Decimal,
maker_fee_percent: Decimal,
}
impl FuturesTradeFee {
pub fn new() -> FuturesTradeFee {
let a = FuturesTradeFee {
user_level: None,
taker_fee_percent: Decimal::new(0, 8),
maker_fee_percent: Decimal::new(0, 8),
};
a
}
}
#[derive(Debug, FromRow, Clone)]
pub struct PositionCoinList {
pub id: u64,
pub order_type: String,
pub status: String,
pub symbol: String,
pub order_id: u64,
pub position: String,
pub registered_server_epoch: i64,
pub transact_time: i64,
pub close_time: i64,
pub used_usdt: Decimal,
pub expected_get_usdt: f64,
pub expected_usdt_profit: f64,
pub entry_price: Decimal,
pub current_price: Decimal,
pub base_qty_ordered: Decimal,
pub base_qty_fee_adjusted: Decimal,
pub pure_profit_percent: f64,
pub minimum_profit_percent: f64,
pub maximum_profit_percent: f64,
}
impl PositionCoinList {
fn new() -> PositionCoinList {
let a = PositionCoinList{
id: 0,
order_type: String::new(),
status: String::new(),
symbol: String::new(),
order_id: 0,
position: String::new(),
registered_server_epoch: 0,
transact_time: 0,
close_time: 0,
used_usdt: Decimal::new(0, 8),
expected_get_usdt: 0.0,
expected_usdt_profit: 0.0,
entry_price: Decimal::new(0, 8),
current_price: Decimal::new(0, 8),
base_qty_ordered: Decimal::new(0, 8),
base_qty_fee_adjusted: Decimal::new(0, 8),
pure_profit_percent: 0.0,
minimum_profit_percent: 0.0,
maximum_profit_percent: 0.0,
};
a
}
}
async fn hmac_signature(query: &mut String) {
// fetch time information from [time] table
let table_name = String::from("time");
let columns = String::from("*");
let condition = None;
let mut time_info = TimeData {
server_epoch: 0,
local_epoch: 0,
epoch_difference: 0,
server_ymdhs: String::new(),
local_ymdhs: String::new(),
last_server_epoch: 0,
last_server_ymdhs: String::new(),
};
let select_result = select_record(&table_name, &columns, &condition, &time_info)
.await
.unwrap();
let difference_epoch = select_result.first().unwrap().epoch_difference;
let server_epoch = select_result.first().unwrap().server_epoch;
// build query message
// local 시간이 server 시간보다 너무 앞서거나 뒤쳐지면 USER_DATA를 요청할 수 없으므로 local과 server 의 시간 차이만큼을 local에서 빼어 보정한 뒤
// 이를 timestamp로 사용한다.
let mut timestamp;
if difference_epoch >= 0 {
timestamp = (server_epoch as u128 + difference_epoch as u128).to_string();
} else if difference_epoch < 0 {
timestamp = (server_epoch as u128 + (difference_epoch * -1) as u128).to_string();
} else {
timestamp = server_epoch.to_string();
}
let recv_window_size = "30000".to_string(); // default: 5,000ms, Max: 60,000ms
let mut query_build = String::from("&timestamp=");
query_build.push_str(&timestamp);
query_build.push_str("&recvWindow=");
query_build.push_str(&recv_window_size);
let mut secret_key = String::new();
unsafe {
if RUNNING_MODE == TEST {
secret_key.push_str(SECRET_KEY_TESTNET);
} else {
secret_key.push_str(SECRET_KEY);
}
}
query.push_str(&query_build);
let signature = HMAC::mac(&query.as_bytes(), secret_key.as_bytes());
query.push_str("&signature=");
query.push_str(signature.encode_hex::<String>().as_str());
}