ctp-dyn 0.1.8

sfit ctp & ctp-mini & ctp-sopt rust native binding with dynlib libloading support, compatible with Linux and macOS
Documentation
#![allow(unused_variables)]
use std::{env::var, path::Path, sync::Arc};

use ctp_dyn::{copy_str_to_i8_array, gb18030_cstr_i8_to_str, print_rsp_info, v1alpha1::*};

pub struct BaseTraderSpi {
    pub tdapi: Arc<TraderApi>,
    pub request_id: i32,
}

impl TraderSpi for BaseTraderSpi {
    fn on_front_connected(&mut self) {
        println!("tdspi.on_front_connected !!!");
        let mut req: CThostFtdcReqAuthenticateField = CThostFtdcReqAuthenticateField::default();
        let user_id = var("SIMNOW_USER0").unwrap();
        copy_str_to_i8_array(&mut req.BrokerID, "9999");
        copy_str_to_i8_array(&mut req.UserID, &user_id);
        copy_str_to_i8_array(&mut req.AppID, "simnow_client_test");
        copy_str_to_i8_array(&mut req.AuthCode, "0000000000000000");

        self.request_id += 1;
        self.tdapi.req_authenticate(&mut req, self.request_id);
    }

    fn on_front_disconnected(&mut self, n_reason: i32) {
        println!("on_front_disconnected: reason{n_reason}")
    }

    fn on_heart_beat_warning(&mut self, n_time_lapse: i32) {}

    fn on_rsp_authenticate(
        &mut self,
        p_rsp_authenticate_field: Option<&CThostFtdcRspAuthenticateField>,
        p_rsp_info: Option<&CThostFtdcRspInfoField>,
        n_request_id: i32,
        b_is_last: bool,
    ) {
        println!("on_rsp_authenticate");
        print_rsp_info!(p_rsp_info);
        if let Some(p_rsp_info) = p_rsp_info {
            if p_rsp_info.ErrorID != 0 {
                return;
            }
        }

        if b_is_last {
            let mut req: CThostFtdcReqUserLoginField = CThostFtdcReqUserLoginField::default();
            let user_id = var("SIMNOW_USER_0").unwrap();
            let password = var("SIMNOW_PASS_0").unwrap();

            copy_str_to_i8_array(&mut req.BrokerID, "9999");
            copy_str_to_i8_array(&mut req.UserID, &user_id);
            copy_str_to_i8_array(&mut req.Password, &password);

            self.request_id += 1;
            #[cfg(not(target_os = "macos"))]
            {
                let ret = self.tdapi.req_user_login(&mut req, self.request_id);
                println!("req_user_login result: {ret}");
            }
            #[cfg(target_os = "macos")]
            {
                let system_info: TThostFtdcClientSystemInfoType = [0; 273];
                let ret = self
                    .tdapi
                    .req_user_login(&mut req, self.request_id, 0, system_info);
                println!("req_user_login result: {ret}");
            }
        }
    }

    fn on_rsp_user_login(
        &mut self,
        p_rsp_user_login: Option<&CThostFtdcRspUserLoginField>,
        p_rsp_info: Option<&CThostFtdcRspInfoField>,
        n_request_id: i32,
        b_is_last: bool,
    ) {
        print_rsp_info!(p_rsp_info);
        if b_is_last {
            let mut req = CThostFtdcSettlementInfoConfirmField::default();
            copy_str_to_i8_array(&mut req.BrokerID, "9999");
            let user_id = var("SIMNOW_USER0").unwrap();
            copy_str_to_i8_array(&mut req.InvestorID, user_id.as_str());

            self.request_id += 1;
            let ret = self
                .tdapi
                .req_settlement_info_confirm(&mut req, self.request_id);
            println!("req_user_login result: {ret}");
        }
    }

    fn on_rsp_settlement_info_confirm(
        &mut self,
        p_settlement_info_confirm: Option<&CThostFtdcSettlementInfoConfirmField>,
        p_rsp_info: Option<&CThostFtdcRspInfoField>,
        n_request_id: i32,
        b_is_last: bool,
    ) {
        print_rsp_info!(p_rsp_info);
        if b_is_last {
            std::thread::sleep(std::time::Duration::from_secs(1));
            self.request_id += 1;
            let mut req = CThostFtdcQryInvestorPositionField::default();
            let ret = self
                .tdapi
                .req_qry_investor_position(&mut req, self.request_id);
            println!("req_qry_investor_position result: {ret}");
        }
    }

    fn on_rsp_qry_investor_position(
        &mut self,
        p_investor_position: Option<&CThostFtdcInvestorPositionField>,
        p_rsp_info: Option<&CThostFtdcRspInfoField>,
        n_request_id: i32,
        b_is_last: bool,
    ) {
        print_rsp_info!(p_rsp_info);
        if let Some(p) = p_investor_position {
            let instrument_id = gb18030_cstr_i8_to_str(&p.InstrumentID).unwrap();
            let user_id = gb18030_cstr_i8_to_str(&p.InvestorID).unwrap();
            println!("{user_id} holds {instrument_id}");
        } else {
            println!("position hold None");
        }
        if b_is_last {
            println!("on_rsp_qry_investor_position finish!");
        }
    }
}

fn sample1() {
    println!("tdapi start here!");
    let base_dir = var("CARGO_MANIFEST_DIR").unwrap();
    println!("base_dir: {base_dir}");

    #[cfg(target_os = "macos")]
    let dynlib_path =
        "./api/ctp/v6.7.2/v6.7.2_MacOS_20231016/thosttraderapi_se.framework/Versions/A/thosttraderapi_se";

    #[cfg(target_os = "linux")]
    let dynlib_path = "./api/v6.7.2/v6.7.2_20230913_api_traderapi_se_linux64/thosttraderapi_se.so";

    let dynlib_path = Path::new(&base_dir).join(dynlib_path);

    let tdapi = TraderApi::create_api(dynlib_path.as_path(), "./td_");
    let tdapi = Arc::new(tdapi);
    let base_tdspi = BaseTraderSpi {
        tdapi: Arc::clone(&tdapi),
        request_id: 0,
    };
    let tdspi_box = Box::new(base_tdspi);
    let tdspi_ptr = Box::into_raw(tdspi_box);
    let tdspi_ptr2 = tdspi_ptr.clone();
    println!("get_api_version: {}", tdapi.get_api_version());

    // tdapi.register_front("tcp://180.168.146.187:10130");
    tdapi.register_front("tcp://180.168.146.187:10201");

    tdapi.register_spi(tdspi_ptr);
    tdapi.subscribe_private_topic(THOST_TE_RESUME_TYPE::THOST_TERT_QUICK);
    tdapi.subscribe_public_topic(THOST_TE_RESUME_TYPE::THOST_TERT_QUICK);

    tdapi.init();

    println!("tdapi init");

    tdapi.join();
    let _ = unsafe { Box::from_raw(tdspi_ptr2) };
}

fn main() {
    let base_dir = var("CARGO_MANIFEST_DIR").unwrap();
    println!("base_dir: {base_dir}");
    sample1();
}