use crate::api::md_api::DepthMarketDataField;
use crate::api::{safe_cstr_to_string, to_cstring, CtpApi};
use crate::error::{CtpError, CtpResult};
use crate::ffi::trader_api::*;
use crate::ffi::{CreateTraderSpiBridge, TraderSpiCallbacks};
use crate::types::{
ExchangeField, InputBatchOrderActionField, InputExecOrderActionField, InputExecOrderField,
InputForQuoteField, InputOrderActionField, InputQuoteActionField, InputQuoteField,
InstrumentCommissionRateField, InstrumentMarginRateField, InvestorPositionDetailField,
NoticeField, OrderActionField, ParkedOrderActionField, ParkedOrderField, ProductField,
QryDepthMarketDataField, QryExchangeField, QryInstrumentCommissionRateField,
QryInstrumentField, QryInstrumentMarginRateField, QryInvestorPositionDetailField,
QryInvestorPositionField, QryMaxOrderVolumeField, QryNoticeField, QryOrderField,
QryProductField, QrySettlementInfoField, QryTradeField, QryTradingAccountField,
QryTransferBankField, RemoveParkedOrderActionField, RemoveParkedOrderField, ReqUserLoginField,
RspInfoField, RspUserLoginField, SettlementInfoConfirmField, SettlementInfoField,
TransferBankField,
};
use std::ffi::c_void;
use std::os::raw::c_int;
use std::ptr;
use std::sync::{Arc, Mutex};
#[allow(dead_code)]
pub struct TraderApi {
api_ptr: *mut c_void,
spi_ptr: *mut c_void,
initialized: bool,
request_id: Arc<Mutex<i32>>,
handler: Option<Box<dyn TraderSpiHandler + Send + Sync>>,
}
#[allow(unused_variables)]
pub trait TraderSpiHandler {
fn on_front_connected(&mut self) {}
fn on_front_disconnected(&mut self, reason: i32) {}
fn on_heart_beat_warning(&mut self, time_lapse: i32) {}
fn on_rsp_authenticate(
&mut self,
rsp_authenticate: Option<RspAuthenticateField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_user_login(
&mut self,
user_login: Option<RspUserLoginField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_user_logout(
&mut self,
user_logout: Option<()>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_error(&mut self, rsp_info: Option<RspInfoField>, request_id: i32, is_last: bool) {}
fn on_rsp_order_insert(
&mut self,
input_order: Option<InputOrderField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_order_action(
&mut self,
input_order_action: Option<InputOrderActionField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rtn_order(&mut self, order: OrderField) {}
fn on_rtn_trade(&mut self, trade: TradeField) {}
fn on_rsp_qry_investor(
&mut self,
investor: Option<InvestorField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_qry_trading_account(
&mut self,
trading_account: Option<TradingAccountField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_qry_investor_position(
&mut self,
investor_position: Option<InvestorPositionField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_qry_instrument(
&mut self,
instrument: Option<InstrumentField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_err_rtn_order_insert(
&mut self,
input_order: Option<InputOrderField>,
rsp_info: Option<RspInfoField>,
) {
}
fn on_err_rtn_order_action(
&mut self,
order_action: Option<OrderActionField>,
rsp_info: Option<RspInfoField>,
) {
}
fn on_rsp_qry_order(
&mut self,
order: Option<OrderField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_qry_trade(
&mut self,
trade: Option<TradeField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_qry_instrument_margin_rate(
&mut self,
margin_rate: Option<InstrumentMarginRateField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_qry_instrument_commission_rate(
&mut self,
commission_rate: Option<InstrumentCommissionRateField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_qry_exchange(
&mut self,
exchange: Option<ExchangeField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_qry_product(
&mut self,
product: Option<ProductField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_settlement_info_confirm(
&mut self,
settlement_info_confirm: Option<SettlementInfoConfirmField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_parked_order_insert(
&mut self,
parked_order: Option<ParkedOrderField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_parked_order_action(
&mut self,
parked_order_action: Option<ParkedOrderActionField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_exec_order_insert(
&mut self,
input_exec_order: Option<InputExecOrderField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_exec_order_action(
&mut self,
input_exec_order_action: Option<InputExecOrderActionField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_for_quote_insert(
&mut self,
input_for_quote: Option<InputForQuoteField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_quote_insert(
&mut self,
input_quote: Option<InputQuoteField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_quote_action(
&mut self,
input_quote_action: Option<InputQuoteActionField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_batch_order_action(
&mut self,
input_batch_order_action: Option<InputBatchOrderActionField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_remove_parked_order(
&mut self,
remove_parked_order: Option<RemoveParkedOrderField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_remove_parked_order_action(
&mut self,
remove_parked_order_action: Option<RemoveParkedOrderActionField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_qry_max_order_volume(
&mut self,
qry_max_order_volume: Option<QryMaxOrderVolumeField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_qry_depth_market_data(
&mut self,
depth_market_data: Option<DepthMarketDataField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_qry_settlement_info(
&mut self,
settlement_info: Option<SettlementInfoField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_qry_transfer_bank(
&mut self,
transfer_bank: Option<TransferBankField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_qry_investor_position_detail(
&mut self,
investor_position_detail: Option<InvestorPositionDetailField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
fn on_rsp_qry_notice(
&mut self,
notice: Option<NoticeField>,
rsp_info: Option<RspInfoField>,
request_id: i32,
is_last: bool,
) {
}
}
#[repr(C)]
#[derive(Debug, Clone)]
pub struct RspAuthenticateField {
pub broker_id: [u8; 11],
pub user_id: [u8; 16],
pub user_product_info: [u8; 11],
pub app_id: [u8; 33],
pub app_type: u8,
}
impl Default for RspAuthenticateField {
fn default() -> Self {
unsafe { std::mem::zeroed() }
}
}
#[repr(C)]
#[derive(Debug, Clone)]
pub struct InputOrderField {
pub broker_id: [u8; 11],
pub investor_id: [u8; 13],
pub instrument_id: [u8; 31],
pub order_ref: [u8; 13],
pub user_id: [u8; 16],
pub order_price_type: u8,
pub direction: u8,
pub comb_offset_flag: [u8; 5],
pub comb_hedge_flag: [u8; 5],
pub limit_price: f64,
pub volume_total_original: i32,
pub time_condition: u8,
pub gtd_date: [u8; 9],
pub volume_condition: u8,
pub min_volume: i32,
pub contingent_condition: u8,
pub stop_price: f64,
pub force_close_reason: u8,
pub is_auto_suspend: i32,
pub business_unit: [u8; 21],
pub request_id: i32,
pub user_force_close: i32,
pub is_swap_order: i32,
pub exchange_id: [u8; 9],
pub invest_unit_id: [u8; 17],
pub account_id: [u8; 13],
pub currency_id: [u8; 4],
pub client_id: [u8; 11],
pub mac_address: [u8; 21],
pub exchange_inst_id: [u8; 31],
pub ip_address: [u8; 16],
}
impl Default for InputOrderField {
fn default() -> Self {
unsafe { std::mem::zeroed() }
}
}
#[repr(C)]
#[derive(Debug, Clone)]
pub struct OrderField {
pub broker_id: [u8; 11],
pub investor_id: [u8; 13],
pub instrument_id: [u8; 31],
pub order_ref: [u8; 13],
pub user_id: [u8; 16],
pub order_price_type: u8,
pub direction: u8,
pub comb_offset_flag: [u8; 5],
pub comb_hedge_flag: [u8; 5],
pub limit_price: f64,
pub volume_total_original: i32,
pub time_condition: u8,
pub gtd_date: [u8; 9],
pub volume_condition: u8,
pub min_volume: i32,
pub contingent_condition: u8,
pub stop_price: f64,
pub force_close_reason: u8,
pub is_auto_suspend: i32,
pub business_unit: [u8; 21],
pub request_id: i32,
pub order_local_id: [u8; 13],
pub exchange_id: [u8; 9],
pub participant_id: [u8; 11],
pub client_id: [u8; 11],
pub exchange_inst_id: [u8; 31],
pub trader_id: [u8; 21],
pub install_id: i32,
pub order_submit_status: u8,
pub notify_sequence: i32,
pub trading_day: [u8; 9],
pub settlement_id: i32,
pub order_sys_id: [u8; 21],
pub order_source: u8,
pub order_status: u8,
pub order_type: u8,
pub volume_traded: i32,
pub volume_total: i32,
pub insert_date: [u8; 9],
pub insert_time: [u8; 9],
pub active_time: [u8; 9],
pub suspend_time: [u8; 9],
pub update_time: [u8; 9],
pub cancel_time: [u8; 9],
pub active_trader_id: [u8; 21],
pub clearing_part_id: [u8; 11],
pub sequence_no: i32,
pub front_id: i32,
pub session_id: i32,
pub user_product_info: [u8; 11],
pub status_msg: [u8; 81],
pub user_force_close: i32,
pub active_user_id: [u8; 16],
pub broker_order_seq: i32,
pub relative_order_sys_id: [u8; 21],
pub zczc_total_traded_volume: i32,
pub is_swap_order: i32,
pub branch_id: [u8; 9],
pub invest_unit_id: [u8; 17],
pub account_id: [u8; 13],
pub currency_id: [u8; 4],
pub mac_address: [u8; 21],
pub ip_address: [u8; 16],
}
impl Default for OrderField {
fn default() -> Self {
unsafe { std::mem::zeroed() }
}
}
#[repr(C)]
#[derive(Debug, Clone)]
pub struct TradeField {
pub broker_id: [u8; 11],
pub investor_id: [u8; 13],
pub instrument_id: [u8; 31],
pub order_ref: [u8; 13],
pub user_id: [u8; 16],
pub exchange_id: [u8; 9],
pub trade_id: [u8; 21],
pub direction: u8,
pub order_sys_id: [u8; 21],
pub participant_id: [u8; 11],
pub client_id: [u8; 11],
pub trading_role: u8,
pub exchange_inst_id: [u8; 31],
pub offset_flag: u8,
pub hedge_flag: u8,
pub price: f64,
pub volume: i32,
pub trade_date: [u8; 9],
pub trade_time: [u8; 9],
pub trade_type: u8,
pub price_source: u8,
pub trader_id: [u8; 21],
pub order_local_id: [u8; 13],
pub clearing_part_id: [u8; 11],
pub business_unit: [u8; 21],
pub sequence_no: i32,
pub trading_day: [u8; 9],
pub settlement_id: i32,
pub broker_order_seq: i32,
pub trade_source: u8,
pub invest_unit_id: [u8; 17],
}
impl Default for TradeField {
fn default() -> Self {
unsafe { std::mem::zeroed() }
}
}
#[repr(C)]
#[derive(Debug, Clone)]
pub struct InvestorField {
pub investor_id: [u8; 13],
pub broker_id: [u8; 11],
pub investor_group_id: [u8; 13],
pub investor_name: [u8; 81],
pub identity_card_type: u8,
pub identity_card_no: [u8; 51],
pub is_active: i32,
pub telephone: [u8; 41],
pub address: [u8; 101],
pub open_date: [u8; 9],
pub mobile: [u8; 41],
pub comm_model_id: [u8; 13],
pub margin_model_id: [u8; 13],
}
impl Default for InvestorField {
fn default() -> Self {
unsafe { std::mem::zeroed() }
}
}
#[repr(C)]
#[derive(Debug, Clone)]
pub struct TradingAccountField {
pub broker_id: [u8; 11],
pub account_id: [u8; 13],
pub pre_mortgage: f64,
pub pre_credit: f64,
pub pre_deposit: f64,
pub pre_balance: f64,
pub pre_margin: f64,
pub interest_base: f64,
pub interest: f64,
pub deposit: f64,
pub withdraw: f64,
pub frozen_margin: f64,
pub frozen_cash: f64,
pub frozen_commission: f64,
pub curr_margin: f64,
pub cash_in: f64,
pub commission: f64,
pub close_profit: f64,
pub position_profit: f64,
pub balance: f64,
pub available: f64,
pub withdraw_quota: f64,
pub reserve: f64,
pub trading_day: [u8; 9],
pub settlement_id: i32,
pub credit: f64,
pub mortgage: f64,
pub exchange_margin: f64,
pub delivery_margin: f64,
pub exchange_delivery_margin: f64,
pub reserve_balance: f64,
pub currency_id: [u8; 4],
pub pre_fund_mortgage_in: f64,
pub pre_fund_mortgage_out: f64,
pub fund_mortgage_in: f64,
pub fund_mortgage_out: f64,
pub fund_mortgage_available: f64,
pub mortgageable_fund: f64,
pub spec_product_margin: f64,
pub spec_product_frozen_margin: f64,
pub spec_product_commission: f64,
pub spec_product_frozen_commission: f64,
pub spec_product_position_profit: f64,
pub spec_product_close_profit: f64,
pub spec_product_position_profit_by_alg: f64,
pub spec_product_exchange_margin: f64,
pub biz_type: u8,
pub frozen_swap: f64,
pub remain_swap: f64,
}
impl Default for TradingAccountField {
fn default() -> Self {
unsafe { std::mem::zeroed() }
}
}
#[repr(C)]
#[derive(Debug, Clone)]
pub struct InvestorPositionField {
pub instrument_id: [u8; 31],
pub broker_id: [u8; 11],
pub investor_id: [u8; 13],
pub posi_direction: u8,
pub hedge_flag: u8,
pub position_date: u8,
pub yd_position: i32,
pub position: i32,
pub long_frozen: i32,
pub short_frozen: i32,
pub long_frozen_amount: f64,
pub short_frozen_amount: f64,
pub open_volume: i32,
pub close_volume: i32,
pub open_amount: f64,
pub close_amount: f64,
pub position_cost: f64,
pub pre_margin: f64,
pub use_margin: f64,
pub frozen_margin: f64,
pub frozen_cash: f64,
pub frozen_commission: f64,
pub cash_in: f64,
pub commission: f64,
pub close_profit: f64,
pub position_profit: f64,
pub pre_settlement_price: f64,
pub settlement_price: f64,
pub trading_day: [u8; 9],
pub settlement_id: i32,
pub open_cost: f64,
pub exchange_margin: f64,
pub comb_position: i32,
pub comb_long_frozen: i32,
pub comb_short_frozen: i32,
pub close_profit_by_date: f64,
pub close_profit_by_trade: f64,
pub today_position: i32,
pub margin_rate_by_money: f64,
pub margin_rate_by_volume: f64,
pub strike_frozen: i32,
pub strike_frozen_amount: f64,
pub abandon_frozen: i32,
pub exchange_id: [u8; 9],
pub yd_strike_frozen: i32,
pub invest_unit_id: [u8; 17],
pub position_cost_offset: f64,
pub tas_position: i32,
pub tas_position_cost: f64,
}
impl Default for InvestorPositionField {
fn default() -> Self {
unsafe { std::mem::zeroed() }
}
}
#[repr(C)]
#[derive(Debug, Clone)]
pub struct InstrumentField {
pub instrument_id: [u8; 31],
pub exchange_id: [u8; 9],
pub instrument_name: [u8; 21],
pub exchange_inst_id: [u8; 31],
pub product_id: [u8; 31],
pub product_class: u8,
pub delivery_year: i32,
pub delivery_month: i32,
pub max_market_order_volume: i32,
pub min_market_order_volume: i32,
pub max_limit_order_volume: i32,
pub min_limit_order_volume: i32,
pub volume_multiple: i32,
pub price_tick: f64,
pub create_date: [u8; 9],
pub open_date: [u8; 9],
pub expire_date: [u8; 9],
pub start_deliv_date: [u8; 9],
pub end_deliv_date: [u8; 9],
pub inst_life_phase: u8,
pub is_trading: i32,
pub position_type: u8,
pub position_date_type: u8,
pub long_margin_ratio: f64,
pub short_margin_ratio: f64,
pub max_margin_side_algorithm: u8,
pub underlying_instr_id: [u8; 31],
pub strike_price: f64,
pub options_type: u8,
pub underlying_multiple: f64,
pub combination_type: u8,
}
impl Default for InstrumentField {
fn default() -> Self {
unsafe { std::mem::zeroed() }
}
}
unsafe impl Send for TraderApi {}
unsafe impl Sync for TraderApi {}
impl TraderApi {
pub fn new(flow_path: Option<&str>, is_production_mode: Option<bool>) -> CtpResult<Self> {
let flow_path_cstr = match flow_path {
Some(path) => Some(to_cstring(path)?),
None => None,
};
let flow_path_ptr = flow_path_cstr
.as_ref()
.map(|s| s.as_ptr())
.unwrap_or(ptr::null());
let production_mode = is_production_mode.unwrap_or(true);
let api_ptr =
unsafe { CThostFtdcTraderApi_CreateFtdcTraderApi(flow_path_ptr, production_mode) };
if api_ptr.is_null() {
return Err(CtpError::InitializationError("创建交易API失败".to_string()));
}
Ok(TraderApi {
api_ptr,
spi_ptr: ptr::null_mut(),
initialized: false,
request_id: Arc::new(Mutex::new(1)),
handler: None,
})
}
pub fn register_spi<T>(&mut self, handler: T) -> CtpResult<()>
where
T: TraderSpiHandler + Send + Sync + 'static,
{
self.handler = Some(Box::new(handler));
let callbacks = TraderSpiCallbacks {
user_data: self as *mut _ as *mut c_void,
on_front_connected: Some(on_front_connected_callback),
on_front_disconnected: Some(on_front_disconnected_callback),
on_heart_beat_warning: Some(on_heart_beat_warning_callback),
on_rsp_authenticate: Some(on_rsp_authenticate_callback),
on_rsp_user_login: Some(on_rsp_user_login_callback),
on_rsp_user_logout: Some(on_rsp_user_logout_callback),
on_rsp_error: Some(on_rsp_error_callback),
on_rsp_order_insert: Some(on_rsp_order_insert_callback),
on_rsp_order_action: Some(on_rsp_order_action_callback),
on_rtn_order: Some(on_rtn_order_callback),
on_rtn_trade: Some(on_rtn_trade_callback),
on_rsp_qry_trading_account: Some(on_rsp_qry_trading_account_callback),
on_rsp_qry_investor_position: Some(on_rsp_qry_investor_position_callback),
on_err_rtn_order_insert: Some(on_err_rtn_order_insert_callback),
on_err_rtn_order_action: Some(on_err_rtn_order_action_callback),
on_rsp_qry_order: Some(on_rsp_qry_order_callback),
on_rsp_qry_trade: Some(on_rsp_qry_trade_callback),
on_rsp_qry_instrument: Some(on_rsp_qry_instrument_callback),
on_rsp_qry_instrument_margin_rate: Some(on_rsp_qry_instrument_margin_rate_callback),
on_rsp_qry_instrument_commission_rate: Some(
on_rsp_qry_instrument_commission_rate_callback,
),
on_rsp_qry_exchange: Some(on_rsp_qry_exchange_callback),
on_rsp_qry_product: Some(on_rsp_qry_product_callback),
on_rsp_settlement_info_confirm: Some(on_rsp_settlement_info_confirm_callback),
on_rsp_parked_order_insert: Some(on_rsp_parked_order_insert_callback),
on_rsp_parked_order_action: Some(on_rsp_parked_order_action_callback),
on_rsp_exec_order_insert: Some(on_rsp_exec_order_insert_callback),
on_rsp_exec_order_action: Some(on_rsp_exec_order_action_callback),
on_rsp_for_quote_insert: Some(on_rsp_for_quote_insert_callback),
on_rsp_quote_insert: Some(on_rsp_quote_insert_callback),
on_rsp_quote_action: Some(on_rsp_quote_action_callback),
on_rsp_batch_order_action: Some(on_rsp_batch_order_action_callback),
on_rsp_remove_parked_order: Some(on_rsp_remove_parked_order_callback),
on_rsp_remove_parked_order_action: Some(on_rsp_remove_parked_order_action_callback),
on_rsp_qry_max_order_volume: Some(on_rsp_qry_max_order_volume_callback),
on_rsp_qry_depth_market_data: Some(on_rsp_qry_depth_market_data_callback),
on_rsp_qry_settlement_info: Some(on_rsp_qry_settlement_info_callback),
on_rsp_qry_transfer_bank: Some(on_rsp_qry_transfer_bank_callback),
on_rsp_qry_investor_position_detail: Some(on_rsp_qry_investor_position_detail_callback),
on_rsp_qry_notice: Some(on_rsp_qry_notice_callback),
};
self.spi_ptr = unsafe { CreateTraderSpiBridge(&callbacks) };
if self.spi_ptr.is_null() {
return Err(CtpError::InitializationError(
"创建交易SPI桥接器失败".to_string(),
));
}
unsafe {
CThostFtdcTraderApi_RegisterSpi(self.api_ptr, self.spi_ptr);
}
Ok(())
}
pub fn req_authenticate(&mut self, req: &ReqAuthenticateField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqAuthenticate(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!("认证请求失败: {}", result)));
}
Ok(request_id)
}
pub fn req_user_login(&mut self, req: &ReqUserLoginField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqUserLogin(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!("登录请求失败: {}", result)));
}
Ok(request_id)
}
pub fn req_user_logout(&mut self) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result =
unsafe { CThostFtdcTraderApi_ReqUserLogout(self.api_ptr, ptr::null(), request_id) };
if result != 0 {
return Err(CtpError::FfiError(format!("登出请求失败: {}", result)));
}
Ok(request_id)
}
pub fn req_qry_trading_account(&mut self, req: &QryTradingAccountField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqQryTradingAccount(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!(
"查询资金账户请求失败: {}",
result
)));
}
Ok(request_id)
}
pub fn req_qry_investor_position(&mut self, req: &QryInvestorPositionField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqQryInvestorPosition(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!(
"查询投资者持仓请求失败: {}",
result
)));
}
Ok(request_id)
}
pub fn req_order_insert(&mut self, req: &InputOrderField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqOrderInsert(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!("报单录入请求失败: {}", result)));
}
Ok(request_id)
}
pub fn req_order_action(&mut self, req: &InputOrderActionField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqOrderAction(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!("报单操作请求失败: {}", result)));
}
Ok(request_id)
}
pub fn req_qry_order(&mut self, req: &QryOrderField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqQryOrder(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!("查询报单请求失败: {}", result)));
}
Ok(request_id)
}
pub fn req_qry_trade(&mut self, req: &QryTradeField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqQryTrade(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!("查询成交请求失败: {}", result)));
}
Ok(request_id)
}
pub fn req_qry_instrument(&mut self, req: &QryInstrumentField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqQryInstrument(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!("查询合约请求失败: {}", result)));
}
Ok(request_id)
}
pub fn req_qry_instrument_margin_rate(
&mut self,
req: &QryInstrumentMarginRateField,
) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqQryInstrumentMarginRate(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!(
"查询合约保证金率请求失败: {}",
result
)));
}
Ok(request_id)
}
pub fn req_qry_instrument_commission_rate(
&mut self,
req: &QryInstrumentCommissionRateField,
) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqQryInstrumentCommissionRate(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!(
"查询合约手续费率请求失败: {}",
result
)));
}
Ok(request_id)
}
pub fn req_qry_exchange(&mut self, req: &QryExchangeField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqQryExchange(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!(
"查询交易所请求失败: {}",
result
)));
}
Ok(request_id)
}
pub fn req_qry_product(&mut self, req: &QryProductField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqQryProduct(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!("查询产品请求失败: {}", result)));
}
Ok(request_id)
}
pub fn req_settlement_info_confirm(
&mut self,
req: &SettlementInfoConfirmField,
) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqSettlementInfoConfirm(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!(
"投资者结算结果确认请求失败: {}",
result
)));
}
Ok(request_id)
}
pub fn req_parked_order_insert(&mut self, req: &ParkedOrderField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqParkedOrderInsert(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!(
"预埋单录入请求失败: {}",
result
)));
}
Ok(request_id)
}
pub fn req_parked_order_action(&mut self, req: &ParkedOrderActionField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqParkedOrderAction(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!(
"预埋撤单录入请求失败: {}",
result
)));
}
Ok(request_id)
}
pub fn req_exec_order_insert(&mut self, req: &InputExecOrderField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqExecOrderInsert(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!(
"执行宣告录入请求失败: {}",
result
)));
}
Ok(request_id)
}
pub fn req_exec_order_action(&mut self, req: &InputExecOrderActionField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqExecOrderAction(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!(
"执行宣告操作请求失败: {}",
result
)));
}
Ok(request_id)
}
pub fn req_for_quote_insert(&mut self, req: &InputForQuoteField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqForQuoteInsert(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!("询价录入请求失败: {}", result)));
}
Ok(request_id)
}
pub fn req_quote_insert(&mut self, req: &InputQuoteField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqQuoteInsert(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!("报价录入请求失败: {}", result)));
}
Ok(request_id)
}
pub fn req_quote_action(&mut self, req: &InputQuoteActionField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqQuoteAction(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!("报价操作请求失败: {}", result)));
}
Ok(request_id)
}
pub fn req_batch_order_action(&mut self, req: &InputBatchOrderActionField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqBatchOrderAction(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!(
"批量报单操作请求失败: {}",
result
)));
}
Ok(request_id)
}
pub fn req_remove_parked_order(&mut self, req: &RemoveParkedOrderField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqRemoveParkedOrder(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!(
"删除预埋单请求失败: {}",
result
)));
}
Ok(request_id)
}
pub fn req_remove_parked_order_action(
&mut self,
req: &RemoveParkedOrderActionField,
) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqRemoveParkedOrderAction(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!(
"删除预埋撤单请求失败: {}",
result
)));
}
Ok(request_id)
}
pub fn req_qry_max_order_volume(&mut self, req: &QryMaxOrderVolumeField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqQryMaxOrderVolume(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!(
"查询最大报单数量请求失败: {}",
result
)));
}
Ok(request_id)
}
pub fn req_qry_depth_market_data(&mut self, req: &QryDepthMarketDataField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqQryDepthMarketData(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!("查询行情请求失败: {}", result)));
}
Ok(request_id)
}
pub fn req_qry_settlement_info(&mut self, req: &QrySettlementInfoField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqQrySettlementInfo(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!(
"查询投资者结算结果请求失败: {}",
result
)));
}
Ok(request_id)
}
pub fn req_qry_transfer_bank(&mut self, req: &QryTransferBankField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqQryTransferBank(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!(
"查询转帐银行请求失败: {}",
result
)));
}
Ok(request_id)
}
pub fn req_qry_investor_position_detail(
&mut self,
req: &QryInvestorPositionDetailField,
) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqQryInvestorPositionDetail(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!(
"查询投资者持仓明细请求失败: {}",
result
)));
}
Ok(request_id)
}
pub fn req_qry_notice(&mut self, req: &QryNoticeField) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let request_id = self.next_request_id();
let result = unsafe {
CThostFtdcTraderApi_ReqQryNotice(
self.api_ptr,
req as *const _ as *const c_void,
request_id,
)
};
if result != 0 {
return Err(CtpError::FfiError(format!(
"查询客户通知请求失败: {}",
result
)));
}
Ok(request_id)
}
fn next_request_id(&self) -> i32 {
let mut id = self.request_id.lock().unwrap();
let current = *id;
*id += 1;
current
}
}
#[repr(C)]
#[derive(Debug, Clone)]
pub struct ReqAuthenticateField {
pub broker_id: [u8; 11],
pub user_id: [u8; 16],
pub user_product_info: [u8; 11],
pub auth_code: [u8; 17],
pub app_id: [u8; 33],
}
impl Default for ReqAuthenticateField {
fn default() -> Self {
unsafe { std::mem::zeroed() }
}
}
impl CtpApi for TraderApi {
fn get_version() -> CtpResult<String> {
let version_ptr = unsafe { CThostFtdcTraderApi_GetApiVersion() };
safe_cstr_to_string(version_ptr)
}
fn init(&mut self) -> CtpResult<()> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API指针为空".to_string()));
}
unsafe {
CThostFtdcTraderApi_Init(self.api_ptr);
}
self.initialized = true;
Ok(())
}
fn release(&mut self) {
if !self.api_ptr.is_null() {
unsafe {
CThostFtdcTraderApi_Release(self.api_ptr);
}
self.api_ptr = ptr::null_mut();
}
self.initialized = false;
}
fn get_trading_day(&self) -> CtpResult<String> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let trading_day_ptr = unsafe { CThostFtdcTraderApi_GetTradingDay(self.api_ptr) };
safe_cstr_to_string(trading_day_ptr)
}
fn register_front(&mut self, front_address: &str) -> CtpResult<()> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let front_address_cstr = to_cstring(front_address)?;
unsafe {
CThostFtdcTraderApi_RegisterFront(self.api_ptr, front_address_cstr.as_ptr());
}
Ok(())
}
fn join(&self) -> CtpResult<i32> {
if self.api_ptr.is_null() {
return Err(CtpError::InitializationError("API未初始化".to_string()));
}
let result = unsafe { CThostFtdcTraderApi_Join(self.api_ptr) };
Ok(result)
}
}
extern "C" fn on_front_connected_callback(user_data: *mut c_void) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
handler.on_front_connected();
}
}
}
}
extern "C" fn on_front_disconnected_callback(user_data: *mut c_void, reason: c_int) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
handler.on_front_disconnected(reason);
}
}
}
}
extern "C" fn on_heart_beat_warning_callback(user_data: *mut c_void, time_lapse: c_int) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
handler.on_heart_beat_warning(time_lapse);
}
}
}
}
extern "C" fn on_rsp_authenticate_callback(
user_data: *mut c_void,
rsp_authenticate: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_rsp_authenticate = if !rsp_authenticate.is_null() {
let auth_ptr = rsp_authenticate as *const RspAuthenticateField;
Some((*auth_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let rsp_ptr = rsp_info as *const RspInfoField;
Some((*rsp_ptr).clone())
} else {
None
};
handler.on_rsp_authenticate(
parsed_rsp_authenticate,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_user_login_callback(
user_data: *mut c_void,
user_login: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_user_login = if !user_login.is_null() {
let login_ptr = user_login as *const RspUserLoginField;
Some((*login_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let rsp_ptr = rsp_info as *const RspInfoField;
Some((*rsp_ptr).clone())
} else {
None
};
handler.on_rsp_user_login(
parsed_user_login,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_user_logout_callback(
user_data: *mut c_void,
_user_logout: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_rsp_info = if !rsp_info.is_null() {
let rsp_ptr = rsp_info as *const RspInfoField;
Some((*rsp_ptr).clone())
} else {
None
};
handler.on_rsp_user_logout(None, parsed_rsp_info, request_id, is_last != 0);
}
}
}
}
extern "C" fn on_rsp_error_callback(
user_data: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_rsp_info = if !rsp_info.is_null() {
let rsp_ptr = rsp_info as *const RspInfoField;
Some((*rsp_ptr).clone())
} else {
None
};
handler.on_rsp_error(parsed_rsp_info, request_id, is_last != 0);
}
}
}
}
extern "C" fn on_rsp_order_insert_callback(
user_data: *mut c_void,
input_order: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_input_order = if !input_order.is_null() {
let order_ptr = input_order as *const InputOrderField;
Some((*order_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let rsp_ptr = rsp_info as *const RspInfoField;
Some((*rsp_ptr).clone())
} else {
None
};
handler.on_rsp_order_insert(
parsed_input_order,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_order_action_callback(
user_data: *mut c_void,
input_order_action: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_input_order_action = if !input_order_action.is_null() {
let action_ptr = input_order_action as *const InputOrderActionField;
Some((*action_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let rsp_ptr = rsp_info as *const RspInfoField;
Some((*rsp_ptr).clone())
} else {
None
};
handler.on_rsp_order_action(
parsed_input_order_action,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rtn_order_callback(user_data: *mut c_void, order: *mut c_void) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
if !order.is_null() {
let order_ptr = order as *const OrderField;
let parsed_order = (*order_ptr).clone();
handler.on_rtn_order(parsed_order);
} else {
let temp_order = OrderField::default();
handler.on_rtn_order(temp_order);
}
}
}
}
}
extern "C" fn on_rtn_trade_callback(user_data: *mut c_void, trade: *mut c_void) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
if !trade.is_null() {
let trade_ptr = trade as *const TradeField;
let parsed_trade = (*trade_ptr).clone();
handler.on_rtn_trade(parsed_trade);
} else {
let temp_trade = TradeField::default();
handler.on_rtn_trade(temp_trade);
}
}
}
}
}
extern "C" fn on_rsp_qry_trading_account_callback(
user_data: *mut c_void,
trading_account: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_trading_account = if !trading_account.is_null() {
let account_ptr = trading_account as *const TradingAccountField;
Some((*account_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_qry_trading_account(
parsed_trading_account,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_qry_investor_position_callback(
user_data: *mut c_void,
investor_position: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_investor_position = if !investor_position.is_null() {
let position_ptr = investor_position as *const InvestorPositionField;
Some((*position_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_qry_investor_position(
parsed_investor_position,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_err_rtn_order_insert_callback(
user_data: *mut c_void,
input_order: *mut c_void,
rsp_info: *mut c_void,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_input_order = if !input_order.is_null() {
let order_ptr = input_order as *const InputOrderField;
Some((*order_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_err_rtn_order_insert(parsed_input_order, parsed_rsp_info);
}
}
}
}
extern "C" fn on_err_rtn_order_action_callback(
user_data: *mut c_void,
order_action: *mut c_void,
rsp_info: *mut c_void,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_order_action = if !order_action.is_null() {
let action_ptr = order_action as *const OrderActionField;
Some((*action_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_err_rtn_order_action(parsed_order_action, parsed_rsp_info);
}
}
}
}
extern "C" fn on_rsp_qry_order_callback(
user_data: *mut c_void,
order: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_order = if !order.is_null() {
let order_ptr = order as *const OrderField;
Some((*order_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_qry_order(parsed_order, parsed_rsp_info, request_id, is_last != 0);
}
}
}
}
extern "C" fn on_rsp_qry_trade_callback(
user_data: *mut c_void,
trade: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_trade = if !trade.is_null() {
let trade_ptr = trade as *const TradeField;
Some((*trade_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_qry_trade(parsed_trade, parsed_rsp_info, request_id, is_last != 0);
}
}
}
}
extern "C" fn on_rsp_qry_instrument_callback(
user_data: *mut c_void,
instrument: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_instrument = if !instrument.is_null() {
let instrument_ptr = instrument as *const InstrumentField;
Some((*instrument_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_qry_instrument(
parsed_instrument,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_qry_instrument_margin_rate_callback(
user_data: *mut c_void,
margin_rate: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_margin_rate = if !margin_rate.is_null() {
let margin_rate_ptr = margin_rate as *const InstrumentMarginRateField;
Some((*margin_rate_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_qry_instrument_margin_rate(
parsed_margin_rate,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_qry_instrument_commission_rate_callback(
user_data: *mut c_void,
commission_rate: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_commission_rate = if !commission_rate.is_null() {
let commission_rate_ptr =
commission_rate as *const InstrumentCommissionRateField;
Some((*commission_rate_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_qry_instrument_commission_rate(
parsed_commission_rate,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_qry_exchange_callback(
user_data: *mut c_void,
exchange: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_exchange = if !exchange.is_null() {
let exchange_ptr = exchange as *const ExchangeField;
Some((*exchange_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_qry_exchange(
parsed_exchange,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_qry_product_callback(
user_data: *mut c_void,
product: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_product = if !product.is_null() {
let product_ptr = product as *const ProductField;
Some((*product_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_qry_product(
parsed_product,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_settlement_info_confirm_callback(
user_data: *mut c_void,
settlement_info_confirm: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_settlement_info_confirm = if !settlement_info_confirm.is_null() {
let settlement_ptr =
settlement_info_confirm as *const SettlementInfoConfirmField;
Some((*settlement_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_settlement_info_confirm(
parsed_settlement_info_confirm,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_parked_order_insert_callback(
user_data: *mut c_void,
parked_order: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_parked_order = if !parked_order.is_null() {
let parked_order_ptr = parked_order as *const ParkedOrderField;
Some((*parked_order_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_parked_order_insert(
parsed_parked_order,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_parked_order_action_callback(
user_data: *mut c_void,
parked_order_action: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_parked_order_action = if !parked_order_action.is_null() {
let parked_action_ptr = parked_order_action as *const ParkedOrderActionField;
Some((*parked_action_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_parked_order_action(
parsed_parked_order_action,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_exec_order_insert_callback(
user_data: *mut c_void,
input_exec_order: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_input_exec_order = if !input_exec_order.is_null() {
let exec_order_ptr = input_exec_order as *const InputExecOrderField;
Some((*exec_order_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_exec_order_insert(
parsed_input_exec_order,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_exec_order_action_callback(
user_data: *mut c_void,
input_exec_order_action: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_input_exec_order_action = if !input_exec_order_action.is_null() {
let exec_action_ptr =
input_exec_order_action as *const InputExecOrderActionField;
Some((*exec_action_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_exec_order_action(
parsed_input_exec_order_action,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_for_quote_insert_callback(
user_data: *mut c_void,
input_for_quote: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_input_for_quote = if !input_for_quote.is_null() {
let for_quote_ptr = input_for_quote as *const InputForQuoteField;
Some((*for_quote_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_for_quote_insert(
parsed_input_for_quote,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_quote_insert_callback(
user_data: *mut c_void,
input_quote: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_input_quote = if !input_quote.is_null() {
let quote_ptr = input_quote as *const InputQuoteField;
Some((*quote_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_quote_insert(
parsed_input_quote,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_quote_action_callback(
user_data: *mut c_void,
input_quote_action: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_input_quote_action = if !input_quote_action.is_null() {
let quote_action_ptr = input_quote_action as *const InputQuoteActionField;
Some((*quote_action_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_quote_action(
parsed_input_quote_action,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_batch_order_action_callback(
user_data: *mut c_void,
input_batch_order_action: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_input_batch_order_action = if !input_batch_order_action.is_null() {
let batch_action_ptr =
input_batch_order_action as *const InputBatchOrderActionField;
Some((*batch_action_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_batch_order_action(
parsed_input_batch_order_action,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_remove_parked_order_callback(
user_data: *mut c_void,
remove_parked_order: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_remove_parked_order = if !remove_parked_order.is_null() {
let remove_ptr = remove_parked_order as *const RemoveParkedOrderField;
Some((*remove_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_remove_parked_order(
parsed_remove_parked_order,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_remove_parked_order_action_callback(
user_data: *mut c_void,
remove_parked_order_action: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_remove_parked_order_action = if !remove_parked_order_action.is_null() {
let remove_action_ptr =
remove_parked_order_action as *const RemoveParkedOrderActionField;
Some((*remove_action_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_remove_parked_order_action(
parsed_remove_parked_order_action,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_qry_max_order_volume_callback(
user_data: *mut c_void,
qry_max_order_volume: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_qry_max_order_volume = if !qry_max_order_volume.is_null() {
let max_volume_ptr = qry_max_order_volume as *const QryMaxOrderVolumeField;
Some((*max_volume_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_qry_max_order_volume(
parsed_qry_max_order_volume,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_qry_depth_market_data_callback(
user_data: *mut c_void,
depth_market_data: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_depth_market_data = if !depth_market_data.is_null() {
let market_data_ptr = depth_market_data as *const DepthMarketDataField;
Some((*market_data_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_qry_depth_market_data(
parsed_depth_market_data,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_qry_settlement_info_callback(
user_data: *mut c_void,
settlement_info: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_settlement_info = if !settlement_info.is_null() {
let settlement_ptr = settlement_info as *const SettlementInfoField;
Some((*settlement_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_qry_settlement_info(
parsed_settlement_info,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_qry_transfer_bank_callback(
user_data: *mut c_void,
transfer_bank: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_transfer_bank = if !transfer_bank.is_null() {
let bank_ptr = transfer_bank as *const TransferBankField;
Some((*bank_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_qry_transfer_bank(
parsed_transfer_bank,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_qry_investor_position_detail_callback(
user_data: *mut c_void,
investor_position_detail: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_investor_position_detail = if !investor_position_detail.is_null() {
let detail_ptr = investor_position_detail as *const InvestorPositionDetailField;
Some((*detail_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_qry_investor_position_detail(
parsed_investor_position_detail,
parsed_rsp_info,
request_id,
is_last != 0,
);
}
}
}
}
extern "C" fn on_rsp_qry_notice_callback(
user_data: *mut c_void,
notice: *mut c_void,
rsp_info: *mut c_void,
request_id: c_int,
is_last: c_int,
) {
unsafe {
if let Some(api) = (user_data as *mut TraderApi).as_mut() {
if let Some(ref mut handler) = api.handler {
let parsed_notice = if !notice.is_null() {
let notice_ptr = notice as *const NoticeField;
Some((*notice_ptr).clone())
} else {
None
};
let parsed_rsp_info = if !rsp_info.is_null() {
let info_ptr = rsp_info as *const RspInfoField;
Some((*info_ptr).clone())
} else {
None
};
handler.on_rsp_qry_notice(parsed_notice, parsed_rsp_info, request_id, is_last != 0);
}
}
}
}
impl Drop for TraderApi {
fn drop(&mut self) {
self.release();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_version() {
match TraderApi::get_version() {
Ok(version) => eprintln!("版本: {}", version),
Err(e) => eprintln!("获取版本失败: {}", e),
}
}
}