use crate::core::types::Symbol;
pub mod proto_id {
pub const INIT_CONNECT: u32 = 1001;
pub const GET_GLOBAL_STATE: u32 = 1002;
pub const KEEP_ALIVE: u32 = 1004;
pub const TRD_GET_ACC_LIST: u32 = 2001;
pub const TRD_UNLOCK_TRADE: u32 = 2004;
pub const TRD_GET_FUNDS: u32 = 2101;
pub const TRD_GET_POSITION_LIST: u32 = 2102;
pub const TRD_GET_ORDER_LIST: u32 = 2201;
pub const TRD_PLACE_ORDER: u32 = 2202;
pub const TRD_MODIFY_ORDER: u32 = 2205;
pub const TRD_GET_ORDER_FILL_LIST: u32 = 2211;
pub const TRD_GET_HIST_ORDER_LIST: u32 = 2221;
pub const TRD_GET_HIST_ORDER_FILL_LIST: u32 = 2231;
pub const QOT_SUB: u32 = 3001;
pub const QOT_GET_STATIC_INFO: u32 = 3004;
pub const QOT_GET_SECURITY_SNAPSHOT: u32 = 3005;
pub const QOT_GET_PLATE_SET: u32 = 3006;
pub const QOT_GET_ORDER_BOOK: u32 = 3012;
pub const QOT_GET_KL: u32 = 3100;
pub const QOT_REQUEST_HISTORY_KL: u32 = 3103;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TrdEnv {
Real = 1,
Simulate = 0,
}
impl TrdEnv {
pub fn as_i32(self) -> i32 {
self as i32
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TrdMarket {
Hk = 1,
Us = 2,
CnSh = 3,
CnSz = 4,
Sg = 11,
}
impl TrdMarket {
pub fn as_i32(self) -> i32 {
self as i32
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SecMarket {
Hk = 1,
Us = 2,
CnSh = 31,
CnSz = 32,
Sg = 41,
}
impl SecMarket {
pub fn as_i32(self) -> i32 {
self as i32
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FutuOrderType {
Normal = 1,
Market = 2,
EnhancedLimit = 3,
StopLimit = 4,
StopMarket = 5,
Auction = 6,
SpecialLimit = 7,
}
impl FutuOrderType {
pub fn as_i32(self) -> i32 {
self as i32
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FutuTrdSide {
Buy = 1,
Sell = 2,
SellShort = 3,
BuyBack = 4,
}
impl FutuTrdSide {
pub fn as_i32(self) -> i32 {
self as i32
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ModifyOrderOp {
Normal = 1,
Cancel = 2,
Disable = 3,
Enable = 4,
Delete = 5,
}
impl ModifyOrderOp {
pub fn as_i32(self) -> i32 {
self as i32
}
}
pub mod order_status {
pub const UNSUBMITTED: i32 = 0;
pub const UNKNOWN: i32 = 1;
pub const WAITING_SUBMIT: i32 = 2;
pub const SUBMITTING: i32 = 3;
pub const SUBMIT_FAILED: i32 = 4;
pub const TIMEOUT: i32 = 5;
pub const SUBMITTED: i32 = 6;
pub const FILLED_PART: i32 = 7;
pub const FILLED_ALL: i32 = 8;
pub const CANCELLING_PART: i32 = 9;
pub const CANCELLING_ALL: i32 = 10;
pub const CANCELLED_PART: i32 = 11;
pub const CANCELLED_ALL: i32 = 12;
pub const FAILED: i32 = 13;
pub const DISABLED: i32 = 14;
pub const DELETED: i32 = 15;
pub const FILL_CANCELLED: i32 = 21;
}
pub struct FutuEndpoints {
pub host: String,
pub port: u16,
pub use_encryption: bool,
}
impl Default for FutuEndpoints {
fn default() -> Self {
Self {
host: "127.0.0.1".to_string(),
port: 11111,
use_encryption: false,
}
}
}
impl FutuEndpoints {
pub fn address(&self) -> String {
format!("{}:{}", self.host, self.port)
}
}
pub fn format_symbol(symbol: &Symbol, market: SecMarket) -> String {
let market_prefix = match market {
SecMarket::Hk => "HK",
SecMarket::Us => "US",
SecMarket::CnSh => "SH",
SecMarket::CnSz => "SZ",
SecMarket::Sg => "SG",
};
format!("{}.{}", market_prefix, symbol.base.to_uppercase())
}
pub fn parse_symbol(futu_code: &str) -> Result<Symbol, String> {
let parts: Vec<&str> = futu_code.splitn(2, '.').collect();
if parts.len() != 2 {
return Err(format!("Invalid Futu code format: {}", futu_code));
}
let quote = match parts[0] {
"HK" => "HKD",
"US" => "USD",
"SH" | "SZ" => "CNY",
"SG" => "SGD",
_ => "USD",
};
Ok(Symbol {
base: parts[1].to_string(),
quote: quote.to_string(),
raw: Some(futu_code.to_string()),
})
}
pub fn infer_sec_market(symbol: &Symbol) -> SecMarket {
if symbol.base.chars().all(|c| c.is_ascii_digit()) {
return SecMarket::Hk;
}
SecMarket::Us
}