19
19
20
20
//! The core `BacktestEngine` for backtesting on historical data.
21
21
22
- use std:: collections:: { HashMap , HashSet , VecDeque } ;
22
+ use std:: {
23
+ cell:: RefCell ,
24
+ collections:: { HashMap , HashSet , VecDeque } ,
25
+ rc:: Rc ,
26
+ } ;
23
27
24
28
use nautilus_core:: { UUID4 , UnixNanos } ;
25
29
use nautilus_execution:: models:: { fee:: FeeModelAny , fill:: FillModel , latency:: LatencyModel } ;
26
30
use nautilus_model:: {
27
31
data:: Data ,
28
32
enums:: { AccountType , BookType , OmsType } ,
29
- identifiers:: { ClientId , InstrumentId , Venue } ,
33
+ identifiers:: { AccountId , ClientId , InstrumentId , Venue } ,
30
34
instruments:: InstrumentAny ,
31
35
types:: { Currency , Money } ,
32
36
} ;
33
37
use nautilus_system:: kernel:: NautilusKernel ;
38
+ use rust_decimal:: Decimal ;
34
39
use ustr:: Ustr ;
35
40
36
41
use crate :: {
37
42
accumulator:: TimeEventAccumulator , config:: BacktestEngineConfig , exchange:: SimulatedExchange ,
38
- modules:: SimulationModule ,
43
+ execution_client :: BacktestExecutionClient , modules:: SimulationModule ,
39
44
} ;
40
45
41
46
pub struct BacktestEngine {
@@ -45,7 +50,7 @@ pub struct BacktestEngine {
45
50
accumulator : TimeEventAccumulator ,
46
51
run_config_id : Option < UUID4 > ,
47
52
run_id : Option < UUID4 > ,
48
- venues : HashMap < Venue , SimulatedExchange > ,
53
+ venues : HashMap < Venue , Rc < RefCell < SimulatedExchange > > > ,
49
54
has_data : HashSet < InstrumentId > ,
50
55
has_book_data : HashSet < InstrumentId > ,
51
56
data : VecDeque < Data > ,
@@ -83,33 +88,87 @@ impl BacktestEngine {
83
88
84
89
#[ allow( clippy:: too_many_arguments) ]
85
90
pub fn add_venue (
86
- & self ,
87
- _venue : Venue ,
88
- _oms_type : OmsType ,
89
- _account_type : AccountType ,
90
- _book_type : BookType ,
91
- _starting_balances : Vec < Money > ,
92
- _base_currency : Option < Currency > ,
93
- _default_leverage : Option < f64 > ,
94
- _leverages : Option < HashMap < Currency , f64 > > ,
95
- _modules : Vec < Box < dyn SimulationModule > > ,
96
- _fill_model : Option < FillModel > ,
97
- _fee_model : Option < FeeModelAny > ,
98
- _latency_model : Option < LatencyModel > ,
99
- _routing : Option < bool > ,
100
- _frozen_account : Option < bool > ,
101
- _reject_stop_orders : Option < bool > ,
102
- _support_gtd_orders : Option < bool > ,
103
- _support_contingent_orders : Option < bool > ,
104
- _use_position_ids : Option < bool > ,
105
- _use_random_ids : Option < bool > ,
106
- _use_reduce_only : Option < bool > ,
107
- _use_message_queue : Option < bool > ,
108
- _bar_execution : Option < bool > ,
109
- _bar_adaptive_high_low_ordering : Option < bool > ,
110
- _trade_execution : Option < bool > ,
91
+ & mut self ,
92
+ venue : Venue ,
93
+ oms_type : OmsType ,
94
+ account_type : AccountType ,
95
+ book_type : BookType ,
96
+ starting_balances : Vec < Money > ,
97
+ base_currency : Option < Currency > ,
98
+ default_leverage : Option < Decimal > ,
99
+ leverages : HashMap < InstrumentId , Decimal > ,
100
+ modules : Vec < Box < dyn SimulationModule > > ,
101
+ fill_model : FillModel ,
102
+ fee_model : FeeModelAny ,
103
+ latency_model : Option < LatencyModel > ,
104
+ routing : Option < bool > ,
105
+ frozen_account : Option < bool > ,
106
+ reject_stop_orders : Option < bool > ,
107
+ support_gtd_orders : Option < bool > ,
108
+ support_contingent_orders : Option < bool > ,
109
+ use_position_ids : Option < bool > ,
110
+ use_random_ids : Option < bool > ,
111
+ use_reduce_only : Option < bool > ,
112
+ use_message_queue : Option < bool > ,
113
+ bar_execution : Option < bool > ,
114
+ bar_adaptive_high_low_ordering : Option < bool > ,
115
+ trade_execution : Option < bool > ,
111
116
) {
112
- todo ! ( "implement add_venue" )
117
+ let default_leverage: Decimal = default_leverage. unwrap_or_else ( || {
118
+ if account_type == AccountType :: Margin {
119
+ Decimal :: from ( 10 )
120
+ } else {
121
+ Decimal :: from ( 0 )
122
+ }
123
+ } ) ;
124
+
125
+ let exchange = SimulatedExchange :: new (
126
+ venue,
127
+ oms_type,
128
+ account_type,
129
+ starting_balances,
130
+ base_currency,
131
+ default_leverage,
132
+ leverages,
133
+ modules,
134
+ self . kernel . cache . clone ( ) ,
135
+ self . kernel . clock . clone ( ) ,
136
+ fill_model,
137
+ fee_model,
138
+ book_type,
139
+ latency_model,
140
+ frozen_account,
141
+ bar_execution,
142
+ reject_stop_orders,
143
+ support_gtd_orders,
144
+ support_contingent_orders,
145
+ use_position_ids,
146
+ use_random_ids,
147
+ use_reduce_only,
148
+ use_message_queue,
149
+ )
150
+ . unwrap ( ) ;
151
+ let exchange = Rc :: new ( RefCell :: new ( exchange) ) ;
152
+ self . venues . insert ( venue, exchange. clone ( ) ) ;
153
+
154
+ let account_id = AccountId :: from ( format ! ( "{}-001" , venue) . as_str ( ) ) ;
155
+ let exec_client = BacktestExecutionClient :: new (
156
+ self . kernel . config . trader_id ,
157
+ account_id,
158
+ exchange. clone ( ) ,
159
+ self . kernel . cache . clone ( ) ,
160
+ self . kernel . clock . clone ( ) ,
161
+ routing,
162
+ frozen_account,
163
+ ) ;
164
+ let exec_client = Rc :: new ( exec_client) ;
165
+
166
+ exchange. borrow_mut ( ) . register_client ( exec_client. clone ( ) ) ;
167
+ self . kernel
168
+ . exec_engine
169
+ . register_client ( exec_client)
170
+ . unwrap ( ) ;
171
+ log:: info!( "Adding exchange {} to engine" , venue) ;
113
172
}
114
173
115
174
pub fn change_fill_model ( & mut self , venue : Venue , fill_model : FillModel ) {
0 commit comments