CTP中,client会收到thost发来的不同类型的信息,包括有来自行情、下单,交易,撤单、查持仓和查合约状况等信息:
OnRtnMarketData
OnRtnOrder
OnRtnTrade
OnErrRtnOrderAction
OnRspOrderInsert
OnRspOrderAction
OnRspQryInvestorPositionDetail
OnRtnInstrumentStatus
这些信息是通过以上的函数异步推送的,当然做策略时,需要把他们同步。
一、信息分发与策略下单
需要考虑具体情况:
一个策略或一个策略组(不同参数组)需要与thost交互;这样,就会在不同的线程间产生大量的不同策略的消息。
(1)这些消息要有序地接收和分发,比如,订阅的信息、交易要与策略一 一相匹配;
(2)在策略与thost发送订单时,需要同步处理;
1、接收thost异步的消息
在策略信息分发部分,可以异步是没问题的。这部分可以考虑用异步的Channel来处理。
下面是试验代码:
use std::thread;
use std::sync::mpsc::channel;
use std::collections::VecDeque;
use std::time::Duration;
use rand::Rng;
use std::sync::mpsc::Receiver;
# [derive(Debug)]
struct Md(u32);
# [derive(Debug)]
struct Insertorder(u32);
# [derive(Debug)]
struct Cancelorder(u32);
# [derive(Debug)]
//模拟thost传过来的不同的值;
enum TradeData{
RtnMarketData(u32),
RntOrder(u32),
RtnTrade(u32),
}
//把rx作为参数传入
fn get_data(rx:&Receiver){
loop{
println!("recv:{:?}",rx.recv().unwrap());
}
}
fn main(){
let (tx,rx) = channel();
//模拟多线程异步进行接收thost相关的行情等信息
for i in 0..10{
let limit = 1050_u32;
let tx = tx.clone();
thread::spawn(move||{
let mut n = 0;
loop{
let rand_value:u32 = rand::thread_rng().gen_range(0, 1000);
n = n +1;
println!("rand_value:{:?} n:{:?} thread id :{:?}",rand_value,n,i);
thread::sleep(Duration::from_millis(100));
match rand_value {
0...600 => tx.send(TradeData::RtnMarketData(rand_value)).unwrap(),
600...900 => tx.send(TradeData::RntOrder(rand_value)).unwrap(),
_ => tx.send(TradeData::RtnTrade(rand_value)).unwrap(),
};
}
});
}
println!("main=>");
get_data(&rx);
thread::sleep(Duration::from_millis(500000));
}
下面是模拟的效果:异步收thost消息,另一个线程异步处理,可以起分发作用。
C#中,可以用 PostMessage+窗体消息函数(WndProc),即策略组(strategGroup)PostMessage消息要发给各自策略内的窗口,策略中的WndProc接收相应的消息。
2、同步不同策略的下单/撤单
在下单和撤单部分,是需要进行同步处理的。可以用:
use std::sync::{Arc,Mutex}
比如:取唯一且自增报单引用,下面是试验代码:
use std::thread;
use std::sync::{Arc,Mutex};
use std::time::Duration;
use rand::Rng;
fn main(){
println!("start!");
let s = Arc::new(Mutex::new(0_u32));
for _ in 0..100{
let s_clone = s.clone();
let temp = *s_clone.lock().unwrap();
thread::spawn(move||{
let rand_value:u64 = rand::thread_rng().gen();
//thread::sleep(Duration::from_millis(rand_value));
*s_clone.lock().unwrap()= temp +1 ;
println!("request_ID:{:?}",*s_clone.lock().unwrap());
}).join();
}
println!("request_id :{:?}",*s.lock().unwrap());
thread::sleep(Duration::from_millis(500000));
}
可以看出,这个锁在100个线程中是起作用的。