在CTP中,CTP thost会异步发送相关行情和交易回报信息给订阅方或策略管理者(这里简称为strategyManager)。那么,模拟一下CTP的机制,有利于在CTP平台上,构建策略交易支持体系。
一、主要涉及几方面:
1、thost异步发送相关信息
利用多线程,多生产者单消费者模式来模拟发送相关信息,可以选用标准库中的mpsc::channel.
2、策略管理者把相关信息发分给不同的策略
二、方案1: 单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;
use std::sync::mpsc::Sender;
use std::thread::Thread;
use std::cell::RefCell;
# [derive(Debug)]
struct RtnMarketData(String);
# [derive(Debug)]
struct RtnOrder(String);
# [derive(Debug)]
struct RtnTrade(String);
//模拟thost传过来的不同的值;
# [derive(Debug)]
enum TradeData{
RtnMarketData(String),
RtnOrder(String),
RtnTrade(String),
}
struct Strategy{
stra_name:String,
stra_thread_builder:thread::Builder,
stra_instructions:Vec,//订阅的相关合约
}
impl Strategy{
fn new(name:String,instrs:Vec)->Self{
Self{
stra_name: name,
stra_thread_builder: thread::Builder::new(),
stra_instructions:instrs,
}
}
fn OnRtnMarketData(&self,md:&TradeData){
println!(" -> strategy:{:?} RtnMarketData=> recv:{:?}",self.stra_name,md);
}
fn OnRtnOrder(&self,order:&TradeData){
println!(" -> strategy:{:?} RtnOrder => recv:{:?}",self.stra_name,order);
}
fn OnRtnTrade(&self,trade:&TradeData){
println!(" -> strategy:{:?} RtnTrade=> recv:{:?}",self.stra_name,trade);
}
}
struct StrategyGroup{
//stra_list : RefCell>,
stra_list : Vec,
}
impl StrategyGroup{
fn new(list:Vec) -> Self{
//stra_list:vec![Strategy::new("DSCJ",vec!["IC","IF"]),Strategy::new("WSDJ",vec!["cu,ag"])]
Self{
//stra_list:RefCell::new(list),
stra_list:list,
}
}
}
struct StrategyManager{
thread_builder : thread::Builder,
stra_group:StrategyGroup,
}
impl StrategyManager{
fn new(group:StrategyGroup)->Self{
Self{
thread_builder : thread::Builder::new(),
stra_group:group,
}
}
}
fn simulate_send(tx:Sender,n_thread:u32){
for i in 0..n_thread {
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(300));
match rand_value {
0...600 => {
match rand_value{
0...100 => tx.send(TradeData::RtnMarketData("IC".to_string())).unwrap(),
100...300=> tx.send(TradeData::RtnMarketData("IF".to_string())).unwrap(),
300...400=> tx.send(TradeData::RtnMarketData("cu".to_string())).unwrap(),
_ =>tx.send(TradeData::RtnMarketData("ag".to_string())).unwrap(),
}
},
600...900 => {
match rand_value{
600...700 =>tx.send(TradeData::RtnOrder("IC".to_string())).unwrap(),
700...750 =>tx.send(TradeData::RtnOrder("IF".to_string())).unwrap(),
750...800 =>tx.send(TradeData::RtnOrder("cu".to_string())).unwrap(),
_ =>tx.send(TradeData::RtnOrder("ag".to_string())).unwrap(),
}
},
_ => {
match rand_value{
900...920 =>tx.send(TradeData::RtnTrade("IC".to_string())).unwrap(),
920...940 =>tx.send(TradeData::RtnTrade("IF".to_string())).unwrap(),
940...960 =>tx.send(TradeData::RtnTrade("cu".to_string())).unwrap(),
_ =>tx.send(TradeData::RtnTrade("ag".to_string())).unwrap(),
}
}
};
}
});
}
}
fn dispatch_data(rx:&Receiver,stra_group:&StrategyGroup){
//let (tx,rx) = channel();
let strategys = &*stra_group.stra_list;
loop{
let ref value = rx.recv().unwrap();
match value {
TradeData::RtnMarketData(d) =>{
for strategy in strategys {
if strategy.stra_instructions.contains(&d){
strategy.OnRtnMarketData(value);
}
}
},
TradeData::RtnOrder(e) =>{
for strategy in strategys {
if strategy.stra_instructions.contains(&e){
strategy.OnRtnOrder(value);
}
}
},
TradeData::RtnTrade(f) =>{
for strategy in strategys {
if strategy.stra_instructions.contains(&f){
strategy.OnRtnTrade(value)
}
}
},
}
}
}
fn generate_strategyManager()-> StrategyManager {
let strategy_01 =Strategy::new("DSCJ".to_string(),vec!["IC".to_string(),"IF".to_string()]);
let strategy_02 =Strategy::new("WSDJ".to_string(),vec!["IF".to_string()]);
let strategy_03 =Strategy::new("TTTT".to_string(),vec!["ag".to_string(),"cu".to_string()]);
let stra_group = StrategyGroup::new(vec![strategy_01,strategy_02,strategy_03]);
StrategyManager::new(stra_group)
}
fn main(){
//模拟生成相关的策略、策略group、策略管理者
let stra_manager = generate_strategyManager();
// 模拟thost
let (tx,rx) = channel::();
//模拟多线程异步进行接收thost相关的行情等信息
simulate_send(tx,10);
println!("main=>");
dispatch_data(&rx,&stra_manager.stra_group);
thread::sleep(Duration::from_millis(500000));
}
三、效果图
在去掉了sleep之后,可以看到,内存一直在上升;因为10个线程不断的发行情,这个压力是很大的;策略的分发的速度又来不及,占用的资源会较大。
这个请大家注意!
五、方案2:多channel + 多线程方案
1、这个模拟,并没有模拟订阅thost的机制;
2、子策略并没有专有线程去接收相关信息;现在是strategyManager中单线程进行分发,并负责策略中信号处理。这部分应交给子策略中的专有线程处理。 即处理的链条过长。
下面的代码实现了两层: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;
use std::sync::mpsc::Sender;
use std::thread::Thread;
use std::sync::{Arc, Mutex};
use std::marker::Send;
use std::cell::RefCell;
# [derive(Debug,Clone)]
struct RtnMarketData(String);
# [derive(Debug,Clone)]
struct RtnOrder(String);
# [derive(Debug,Clone)]
struct RtnTrade(String);
# [derive(Debug,Clone)]
enum TradeData{
RtnMarketData(String),
RtnOrder(String),
RtnTrade(String),
}
trait Get_id{
fn get_request_id(&self)-> u32;
}
struct Strategy{
stra_name:String,
receiver:Receiver,
lock:Arc>,
}
struct StrategyHandler{
stra_name: String,
stra_instructions: Vec, //订阅的相关合约
sender:Sender,
}
impl StrategyHandler{
fn new(name:String,instrs:Vec,send:Sender)->Self{
Self{
stra_name: name,
stra_instructions: instrs,
sender:send,
}
}
}
impl Strategy{
fn new(name:String,recv:Receiver,lock:Arc>)->Self{
Self{
stra_name:name,
receiver:recv,
lock:lock,
}
}
fn spawn(self){
thread::spawn(move||{
loop{
let value = self.receiver.recv().unwrap();
match value {
TradeData::RtnMarketData(_) =>{
self.OnRtnMarketData(value);
},
TradeData::RtnOrder(_) =>{
self.OnRtnOrder(value);
},
TradeData::RtnTrade(_) =>{
self.OnRtnTrade(value);
},
}
};
});
}
fn OnRtnMarketData(&self,md:TradeData){
println!(" -> strategy:{:?} RtnMarketData=> recv:{:?}",self.stra_name,md);
let rand_value:u64 = rand::thread_rng().gen_range(200,500);
// 获取唯一ID,策略逻辑在此
if rand_value < 400 {
println!("触发交易信号:{:?} id:{:?}",rand_value,self.get_request_id());
}
thread::sleep(Duration::from_millis(rand_value));
}
fn OnRtnOrder(&self,order:TradeData){
println!(" -> strategy:{:?} RtnOrder => recv:{:?}",self.stra_name,order);
let rand_value:u64 = rand::thread_rng().gen_range(200,500);
// 获取唯一ID
if rand_value < 10 {
println!("触发OnRtnOrder信号:{:?} id:{:?}",rand_value,self.get_request_id());
}
}
fn OnRtnTrade(&self,trade:TradeData){
println!(" -> strategy:{:?} RtnTrade=> recv:{:?}",self.stra_name,trade);
let rand_value:u64 = rand::thread_rng().gen_range(200,500);
// 获取唯一ID
if rand_value < 300 {
println!("触发OnRtnTrade信号:{:?} id:{:?}",rand_value,self.get_request_id());
}
}
}
impl Get_id for Strategy{
fn get_request_id(&self)-> u32{
let lock = self.lock.clone();
let temp = *lock.lock().unwrap();
*lock.lock().unwrap()= temp +1 ;
println!("request_ID:{:?}",*lock.lock().unwrap());
temp+1
}
}
struct StrategyGroup{
stra_list : Vec,
}
impl StrategyGroup{
fn new(list:Vec) -> Self{
Self{
stra_list:list,
}
}
}
struct StrategyManager{
stra_group: StrategyGroup,
}
impl StrategyManager{
fn new(group: StrategyGroup)->Self{
Self{
stra_group: group,
}
}
}
fn simulate_send(tx:Sender,n_thread:u32){
for i in 0..n_thread {
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!("thost send info: thread id :{:?} ,次数 {:?} ",i,n);
thread::sleep(Duration::from_millis(500));
match rand_value {
0...600 => {
match rand_value{
0...100 => tx.send(TradeData::RtnMarketData("IC".to_string())).unwrap(),
100...300=> tx.send(TradeData::RtnMarketData("IF".to_string())).unwrap(),
300...400=> tx.send(TradeData::RtnMarketData("cu".to_string())).unwrap(),
_ =>tx.send(TradeData::RtnMarketData("ag".to_string())).unwrap(),
}
},
600...900 => {
match rand_value{
600...700 =>tx.send(TradeData::RtnOrder("IC".to_string())).unwrap(),
700...750 =>tx.send(TradeData::RtnOrder("IF".to_string())).unwrap(),
750...800 =>tx.send(TradeData::RtnOrder("cu".to_string())).unwrap(),
_ =>tx.send(TradeData::RtnOrder("ag".to_string())).unwrap(),
}
},
_ => {
match rand_value{
900...920 =>tx.send(TradeData::RtnTrade("IC".to_string())).unwrap(),
920...940 =>tx.send(TradeData::RtnTrade("IF".to_string())).unwrap(),
940...960 =>tx.send(TradeData::RtnTrade("cu".to_string())).unwrap(),
_ =>tx.send(TradeData::RtnTrade("ag".to_string())).unwrap(),
}
}
};
}
});
}
//thost::new(tx).thost_thread_builder.spawn()
}
fn dispatch_data(rx:&Receiver,_handlers: Vec){
let handlers = &_handlers;
loop{
let ref value = rx.recv().unwrap();
match value {
TradeData::RtnMarketData(d) =>{
for handler in handlers {
if handler.stra_instructions.contains(&d){
//strategy.OnRtnMarketData(value)
let tx = handler.sender.clone();
tx.send(TradeData::RtnMarketData(d.to_string())).unwrap();
println!("dispatch:{:?}",d);
}
}
},
TradeData::RtnOrder(e) =>{
for handler in handlers {
if handler.stra_instructions.contains(&e){
let tx = handler.sender.clone();
tx.send(TradeData::RtnOrder(e.to_string())).unwrap();
println!("dispatch:{:?}",e);
}
}
},
TradeData::RtnTrade(f) =>{
for handler in handlers {
if handler.stra_instructions.contains(&f){
let tx = handler.sender.clone();
tx.send(TradeData::RtnTrade(f.to_string())).unwrap();
println!("dispatch:{:?}",f);
}
}
},
}
}
}
fn strategy_init()-> Vec {
let (tx_01,rx_01) = channel::();
let (tx_02,rx_02) = channel::();
let (tx_03,rx_03) = channel::();
let id = Arc::new(Mutex::new(0_u32));
let stra_handler_01 = StrategyHandler::new("DSCJ".to_string(),vec!["IC".to_string(),"IH".to_string()],tx_01);
let strategy_01 = Strategy::new("DSCJ".to_string(),rx_01,id.clone());
println!("a");
strategy_01.spawn();
println!("b");
let stra_handler_02 = StrategyHandler::new("TTTT".to_string(),vec!["IC".to_string(),"IF".to_string()],tx_02);
let strategy_02 = Strategy::new("TTTT".to_string(),rx_02,id.clone());
strategy_02.spawn();
let stra_handler_03 = StrategyHandler::new("WSDJ".to_string(),vec!["ag".to_string(),"cu".to_string()],tx_03);
let strategy_03 = Strategy::new("WSDJ".to_string(),rx_03,id.clone());
strategy_03.spawn();
vec![stra_handler_01,stra_handler_02,stra_handler_03]
}
// 等待=>
fn main(){
//模拟生成相关的策略、策略group、策略管理者
let handlers :Vec = strategy_init();
//模拟thost
let (tx,rx) = channel::();
//模拟N个多线程异步进行接收thost相关的行情等信息
simulate_send(tx,2);
println!("main=>");
dispatch_data(&rx,handlers);
thread::sleep(Duration::from_millis(500000));
}
上面的核心是:sender:Sender < TradeData >和 Receiver < TradeData >要分离,否则在启新线程中,就会把策略本身move进行。
上面不仅有多线程和异步接收相关的信息,而且还有同步交易的模拟,在功能上也比较完整。
六、方法3:单channel +多线程方案
当然,用channel很方便,但有没有简单用加锁的方式,来解决这个问题?
有的,但是架构上,仍二个Arc(Mutex< > ) 放在分开的两部分之中。
下面是代码:
use std::thread;
use std::sync::mpsc::channel;
use std::collections::VecDeque;
use std::time::Duration;
use rand::Rng;
use std::sync::mpsc::Receiver;
use std::sync::mpsc::Sender;
use std::thread::Thread;
use std::sync::{Arc, Mutex};
use std::marker::Send;
use std::cell::RefCell;
# [derive(Debug,Clone)]
struct RtnMarketData(String);
# [derive(Debug,Clone)]
struct RtnOrder(String);
# [derive(Debug,Clone)]
struct RtnTrade(String);
# [derive(Debug,Clone)]
enum TradeData{
RtnMarketData(String),
RtnOrder(String),
RtnTrade(String),
}
trait Get_id{
fn get_request_id(&self)-> u32;
}
trait Get_data{
fn push_data(&self,td:TradeData);
}
struct Strategy{
stra_name:String,
stra_instructions: Vec, //订阅的相关合约
lock_id:Arc>,
lock_data:Arc>>,
}
struct Handler{
stra_name:String,
stra_instructions: Vec, //订阅的相关合约
lock_data:Arc>>,
}
impl Handler{
fn new(name:String,instrs:Vec,lock_data:Arc>>)->Self{
Self{
stra_name:name,
stra_instructions: instrs, //订阅的相关合约
lock_data:lock_data,
}
}
}
impl Get_data for Handler{
fn push_data(&self,td:TradeData){
let s_clone = self.lock_data.clone();
if s_clone.is_poisoned(){
println!("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ get_data posion:{:?}",s_clone.is_poisoned());
}
let mut guard = match s_clone.lock() {
Ok(guard) => guard,
Err(poisoned) => {
println!(" posion!");
poisoned.into_inner()
},
};
println!("push_back 成功!:{:?}",td);
guard.push_back(td);
}
}
impl Strategy{
fn new(name:String,instrs:Vec,lock_id:Arc>,lock_data:Arc>>)->Self{
Self{
stra_name:name,
stra_instructions: instrs, //订阅的相关合约
lock_id: lock_id,
lock_data:lock_data,
}
}
fn spawn(self){
let lock = self.lock_data.clone();
if lock.is_poisoned(){
println!("=======================================> spawn posion:{:?}",lock.is_poisoned());
}
thread::spawn(move||{
loop{
let value = lock.lock().unwrap().pop_back();//.unwrap();//front
println!("=> get value:{:?}",value);
thread::sleep(Duration::from_millis(100));
match value {
Some(TradeData::RtnMarketData(d)) =>{
self.OnRtnMarketData(TradeData::RtnMarketData(d));
},
Some(TradeData::RtnOrder(e)) =>{
self.OnRtnOrder(TradeData::RtnOrder(e));
},
Some(TradeData::RtnTrade(f)) =>{
self.OnRtnTrade(TradeData::RtnTrade(f));
},
_ =>{
println!("其它数据类型:{:?}",value);
continue;
},
}
};
});
}
fn OnRtnMarketData(&self,md:TradeData){
println!(" -> strategy:{:?} RtnMarketData=> recv:{:?}",self.stra_name,md);
let rand_value:u64 = rand::thread_rng().gen_range(200,500);
// 交易获取唯一ID
if rand_value < 400 {
println!("触发交易信号:{:?} id:{:?}",rand_value,self.get_request_id());
}
thread::sleep(Duration::from_millis(rand_value));
}
fn OnRtnOrder(&self,order:TradeData){
println!(" -> strategy:{:?} RtnOrder => recv:{:?}",self.stra_name,order);
let rand_value:u64 = rand::thread_rng().gen_range(200,500);
// 交易获取唯一ID
if rand_value < 10 {
println!("触发OnRtnOrder信号:{:?} id:{:?}",rand_value,self.get_request_id());
}
}
fn OnRtnTrade(&self,trade:TradeData){
println!(" -> strategy:{:?} RtnTrade=> recv:{:?}",self.stra_name,trade);
let rand_value:u64 = rand::thread_rng().gen_range(200,500);
// 交易获取唯一ID
if rand_value < 300 {
println!("触发OnRtnTrade信号:{:?} id:{:?}",rand_value,self.get_request_id());
}
}
}
impl Get_id for Strategy{
fn get_request_id(&self)-> u32{
let lock = self.lock_id.clone();
let temp = *lock.lock().unwrap();
*lock.lock().unwrap()= temp +1 ;
println!("request_ID:{:?}",*lock.lock().unwrap());
temp + 1
}
}
struct StrategyGroup{
stra_list : Vec,
}
impl StrategyGroup{
fn new(list:Vec) -> Self{
Self{
stra_list:list,
}
}
}
struct StrategyManager{
stra_group: StrategyGroup,
}
impl StrategyManager{
fn new(group: StrategyGroup)->Self{
Self{
stra_group: group,
}
}
}
fn simulate_send(tx:Sender,n_thread:u32){
for i in 0..n_thread {
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!("thost send info: thread id :{:?} ,次数 {:?} ",i,n);
thread::sleep(Duration::from_millis(50));
match rand_value {
0...600 => {
match rand_value{
0...100 => tx.send(TradeData::RtnMarketData("IC".to_string())).unwrap(),
100...300=> tx.send(TradeData::RtnMarketData("IF".to_string())).unwrap(),
300...400=> tx.send(TradeData::RtnMarketData("cu".to_string())).unwrap(),
_ =>tx.send(TradeData::RtnMarketData("ag".to_string())).unwrap(),
}
},
600...900 => {
match rand_value{
600...700 =>tx.send(TradeData::RtnOrder("IC".to_string())).unwrap(),
700...750 =>tx.send(TradeData::RtnOrder("IF".to_string())).unwrap(),
750...800 =>tx.send(TradeData::RtnOrder("cu".to_string())).unwrap(),
_ =>tx.send(TradeData::RtnOrder("ag".to_string())).unwrap(),
}
},
_ => {
match rand_value{
900...920 =>tx.send(TradeData::RtnTrade("IC".to_string())).unwrap(),
920...940 =>tx.send(TradeData::RtnTrade("IF".to_string())).unwrap(),
940...960 =>tx.send(TradeData::RtnTrade("cu".to_string())).unwrap(),
_ =>tx.send(TradeData::RtnTrade("ag".to_string())).unwrap(),
}
}
};
}
});
}
//thost::new(tx).thost_thread_builder.spawn()
}
fn dispatch_data(rx:&Receiver,ss: Vec){
let ss = &ss;
loop{
let ref value = rx.recv().unwrap();
match value {
TradeData::RtnMarketData(d) =>{
for s in ss {
if s.stra_instructions.contains(&d){
println!("dispatch 2:{:?}",d);
s.push_data(TradeData::RtnMarketData(d.to_string()));
}
}
},
TradeData::RtnOrder(e) =>{
for s in ss {
if s.stra_instructions.contains(&e){
println!("dispatch 4:{:?}",e);
s.push_data(TradeData::RtnOrder(e.to_string()));
}
}
},
TradeData::RtnTrade(f) =>{
for s in ss {
if s.stra_instructions.contains(&f){
println!("dispatch 6:{:?}",f);
s.push_data(TradeData::RtnTrade(f.to_string()));
}
}
},
}
}
}
fn strategy_init()-> Vec {
let id = Arc::new(Mutex::new(0_u32));
let v_01 :VecDeque = VecDeque::new();
let data_01 = Arc::new(Mutex::new(v_01));
let v_02 :VecDeque = VecDeque::new();
let data_02 = Arc::new(Mutex::new(v_02));
let v_03 :VecDeque = VecDeque::new();
let data_03 = Arc::new(Mutex::new(v_03));
let handler_01 = Handler::new("DSCJ".to_string(),vec!["IC".to_string(),"IF".to_string()],data_01.clone());
let strategy_01 = Strategy::new("DSCJ".to_string(),vec!["IC".to_string(),"IF".to_string()],id.clone(),data_01.clone());
strategy_01.spawn();
let handler_02 = Handler::new("TTTT".to_string(),vec!["IC".to_string(),"IH".to_string()],data_02.clone());
let strategy_02 = Strategy::new("TTTT".to_string(),vec!["IC".to_string(),"IH".to_string()],id.clone(),data_02.clone());
strategy_02.spawn();
let handler_03 = Handler::new("WSDJ".to_string(),vec!["cu".to_string(),"ag".to_string()],data_03.clone());
let strategy_03 = Strategy::new("WSDJ".to_string(),vec!["cu".to_string(),"ag".to_string()],id.clone(),data_03.clone());
strategy_03.spawn();
vec![handler_01,handler_02,handler_03]
}
fn main(){
//模拟生成相关的策略、策略group、策略管理者
let handlers :Vec = strategy_init();
//模拟thost
let (tx,rx) = channel::();
//模拟N个多线程异步进行接收thost相关的行情等信息
simulate_send(tx,2);
println!("main=>");
dispatch_data(&rx,handlers);
thread::sleep(Duration::from_millis(500000));
}