back-trader-python 1.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (465) hide show
  1. back_trader_python-1.4.0.dist-info/METADATA +1491 -0
  2. back_trader_python-1.4.0.dist-info/RECORD +465 -0
  3. back_trader_python-1.4.0.dist-info/WHEEL +5 -0
  4. back_trader_python-1.4.0.dist-info/licenses/LICENSE +674 -0
  5. back_trader_python-1.4.0.dist-info/top_level.txt +1 -0
  6. backtrader/__init__.py +148 -0
  7. backtrader/_cerebro/__init__.py +5 -0
  8. backtrader/_cerebro/channel.py +382 -0
  9. backtrader/_cerebro/execution.py +377 -0
  10. backtrader/_cerebro/lifecycle.py +143 -0
  11. backtrader/_cerebro/notifications.py +150 -0
  12. backtrader/_cerebro/presentation.py +230 -0
  13. backtrader/_cerebro/registry.py +593 -0
  14. backtrader/_cerebro/runnext.py +551 -0
  15. backtrader/_cerebro/runonce.py +142 -0
  16. backtrader/analyzer.py +594 -0
  17. backtrader/analyzers/__init__.py +50 -0
  18. backtrader/analyzers/annualreturn.py +226 -0
  19. backtrader/analyzers/calmar.py +165 -0
  20. backtrader/analyzers/drawdown.py +287 -0
  21. backtrader/analyzers/leverage.py +112 -0
  22. backtrader/analyzers/logreturnsrolling.py +190 -0
  23. backtrader/analyzers/periodstats.py +153 -0
  24. backtrader/analyzers/positions.py +119 -0
  25. backtrader/analyzers/pyfolio.py +470 -0
  26. backtrader/analyzers/returns.py +192 -0
  27. backtrader/analyzers/sharpe.py +307 -0
  28. backtrader/analyzers/sharpe_ratio_stats.py +534 -0
  29. backtrader/analyzers/sqn.py +112 -0
  30. backtrader/analyzers/timereturn.py +192 -0
  31. backtrader/analyzers/total_value.py +75 -0
  32. backtrader/analyzers/tradeanalyzer.py +278 -0
  33. backtrader/analyzers/transactions.py +141 -0
  34. backtrader/analyzers/vwr.py +245 -0
  35. backtrader/bokeh/__init__.py +155 -0
  36. backtrader/bokeh/analyzers/__init__.py +13 -0
  37. backtrader/bokeh/analyzers/plot.py +192 -0
  38. backtrader/bokeh/analyzers/recorder.py +181 -0
  39. backtrader/bokeh/app.py +1094 -0
  40. backtrader/bokeh/live/__init__.py +11 -0
  41. backtrader/bokeh/live/client.py +352 -0
  42. backtrader/bokeh/live/datahandler.py +346 -0
  43. backtrader/bokeh/plot_adapter.py +200 -0
  44. backtrader/bokeh/schemes/__init__.py +14 -0
  45. backtrader/bokeh/schemes/blackly.py +76 -0
  46. backtrader/bokeh/schemes/scheme.py +150 -0
  47. backtrader/bokeh/schemes/tradimo.py +82 -0
  48. backtrader/bokeh/tab.py +125 -0
  49. backtrader/bokeh/tabs/__init__.py +30 -0
  50. backtrader/bokeh/tabs/analyzer.py +120 -0
  51. backtrader/bokeh/tabs/config.py +154 -0
  52. backtrader/bokeh/tabs/live.py +109 -0
  53. backtrader/bokeh/tabs/log.py +185 -0
  54. backtrader/bokeh/tabs/metadata.py +182 -0
  55. backtrader/bokeh/tabs/performance.py +359 -0
  56. backtrader/bokeh/tabs/source.py +70 -0
  57. backtrader/bokeh/utils/__init__.py +8 -0
  58. backtrader/bokeh/utils/helpers.py +167 -0
  59. backtrader/bokeh/webapp.py +164 -0
  60. backtrader/broker.py +478 -0
  61. backtrader/brokers/__init__.py +36 -0
  62. backtrader/brokers/bbroker.py +2576 -0
  63. backtrader/brokers/btapibroker.py +8227 -0
  64. backtrader/brokers/hft/__init__.py +89 -0
  65. backtrader/brokers/hft/binance_bbo.py +625 -0
  66. backtrader/brokers/hft/binance_bbo_compare.py +1398 -0
  67. backtrader/brokers/hft/examples.py +1228 -0
  68. backtrader/brokers/hft/exchange.py +380 -0
  69. backtrader/brokers/hft/latency.py +309 -0
  70. backtrader/brokers/hft/matching_core.py +572 -0
  71. backtrader/brokers/hft/queue.py +238 -0
  72. backtrader/brokers/hft/recorder.py +88 -0
  73. backtrader/brokers/hft/state.py +138 -0
  74. backtrader/brokers/impact_models.py +118 -0
  75. backtrader/brokers/mixbroker.py +895 -0
  76. backtrader/brokers/tickbroker.py +1991 -0
  77. backtrader/btrun/__init__.py +12 -0
  78. backtrader/btrun/btrun.py +1218 -0
  79. backtrader/cerebro.py +828 -0
  80. backtrader/channel.py +682 -0
  81. backtrader/channels/__init__.py +23 -0
  82. backtrader/channels/bridge.py +186 -0
  83. backtrader/channels/funding.py +248 -0
  84. backtrader/channels/live_queue.py +216 -0
  85. backtrader/channels/live_validator.py +294 -0
  86. backtrader/channels/orderbook.py +257 -0
  87. backtrader/channels/tick.py +202 -0
  88. backtrader/comminfo.py +665 -0
  89. backtrader/commissions/__init__.py +106 -0
  90. backtrader/commissions/ctpoption.py +993 -0
  91. backtrader/configs/account_config_example.yaml +8 -0
  92. backtrader/dataseries.py +379 -0
  93. backtrader/errors.py +106 -0
  94. backtrader/events.py +980 -0
  95. backtrader/feed.py +1523 -0
  96. backtrader/feeds/__init__.py +75 -0
  97. backtrader/feeds/barrier.py +2006 -0
  98. backtrader/feeds/blaze.py +118 -0
  99. backtrader/feeds/btapifeed.py +1538 -0
  100. backtrader/feeds/btcsv.py +203 -0
  101. backtrader/feeds/chainer.py +114 -0
  102. backtrader/feeds/cryptohftdata.py +164 -0
  103. backtrader/feeds/csvgeneric.py +1205 -0
  104. backtrader/feeds/ctpcohort.py +1051 -0
  105. backtrader/feeds/influxfeed.py +158 -0
  106. backtrader/feeds/livefeed.py +71 -0
  107. backtrader/feeds/mixed_channel.py +108 -0
  108. backtrader/feeds/mt4csv.py +42 -0
  109. backtrader/feeds/pandafeed.py +381 -0
  110. backtrader/feeds/quandl.py +256 -0
  111. backtrader/feeds/rollover.py +229 -0
  112. backtrader/feeds/sierrachart.py +30 -0
  113. backtrader/feeds/vchart.py +162 -0
  114. backtrader/feeds/vchartcsv.py +84 -0
  115. backtrader/feeds/vchartfile.py +153 -0
  116. backtrader/feeds/yahoo.py +399 -0
  117. backtrader/fillers.py +148 -0
  118. backtrader/filters/__init__.py +34 -0
  119. backtrader/filters/bsplitter.py +127 -0
  120. backtrader/filters/calendardays.py +121 -0
  121. backtrader/filters/datafiller.py +192 -0
  122. backtrader/filters/datafilter.py +74 -0
  123. backtrader/filters/daysteps.py +96 -0
  124. backtrader/filters/heikinashi.py +63 -0
  125. backtrader/filters/renko.py +164 -0
  126. backtrader/filters/session.py +289 -0
  127. backtrader/flt.py +80 -0
  128. backtrader/functions.py +960 -0
  129. backtrader/indicator.py +449 -0
  130. backtrader/indicators/__init__.py +148 -0
  131. backtrader/indicators/accdecoscillator.py +110 -0
  132. backtrader/indicators/aroon.py +300 -0
  133. backtrader/indicators/atr.py +315 -0
  134. backtrader/indicators/awesomeoscillator.py +122 -0
  135. backtrader/indicators/basicops.py +834 -0
  136. backtrader/indicators/bollinger.py +223 -0
  137. backtrader/indicators/cci.py +89 -0
  138. backtrader/indicators/channels_ext.py +83 -0
  139. backtrader/indicators/contrib/__init__.py +228 -0
  140. backtrader/indicators/contrib/absolutely_no_lag_lwma.py +28 -0
  141. backtrader/indicators/contrib/absolutely_no_lag_lwma_color.py +44 -0
  142. backtrader/indicators/contrib/accumulation_distribution_line.py +92 -0
  143. backtrader/indicators/contrib/adx_cross_hull_style_indicator.py +249 -0
  144. backtrader/indicators/contrib/adxdmi.py +34 -0
  145. backtrader/indicators/contrib/ai_acceleration_deceleration_oscillator.py +34 -0
  146. backtrader/indicators/contrib/altr_trend_signal_v22.py +85 -0
  147. backtrader/indicators/contrib/anchored_momentum_line.py +115 -0
  148. backtrader/indicators/contrib/any_range_cld_tail_indicator.py +82 -0
  149. backtrader/indicators/contrib/aroon_horn_sign_indicator.py +96 -0
  150. backtrader/indicators/contrib/aroon_oscillator_sign_alert.py +50 -0
  151. backtrader/indicators/contrib/arrows_curves_indicator.py +112 -0
  152. backtrader/indicators/contrib/as_ctrend_indicator.py +143 -0
  153. backtrader/indicators/contrib/asimmetric_stoch_nr_indicator.py +187 -0
  154. backtrader/indicators/contrib/atr_normalize_histogram.py +118 -0
  155. backtrader/indicators/contrib/average_change_candle.py +165 -0
  156. backtrader/indicators/contrib/bb_squeeze_indicator.py +60 -0
  157. backtrader/indicators/contrib/bezier_st_dev_indicator.py +135 -0
  158. backtrader/indicators/contrib/binary_wave_indicator.py +233 -0
  159. backtrader/indicators/contrib/blau_c_momentum_indicator.py +123 -0
  160. backtrader/indicators/contrib/blau_cmi_indicator.py +141 -0
  161. backtrader/indicators/contrib/blau_csi.py +76 -0
  162. backtrader/indicators/contrib/blau_ergodic.py +53 -0
  163. backtrader/indicators/contrib/blau_t_stoch_i.py +72 -0
  164. backtrader/indicators/contrib/blau_ts_stochastic.py +85 -0
  165. backtrader/indicators/contrib/blau_tvi.py +55 -0
  166. backtrader/indicators/contrib/brain_trend2_indicator.py +128 -0
  167. backtrader/indicators/contrib/brain_trend_signal_proxy.py +47 -0
  168. backtrader/indicators/contrib/brake_parb_indicator.py +85 -0
  169. backtrader/indicators/contrib/breakout_bars_trend_v2.py +121 -0
  170. backtrader/indicators/contrib/bsi_indicator.py +87 -0
  171. backtrader/indicators/contrib/bulls_bears_eyes.py +67 -0
  172. backtrader/indicators/contrib/bulls_power.py +56 -0
  173. backtrader/indicators/contrib/bw_wise_man1_signal.py +102 -0
  174. backtrader/indicators/contrib/bykov_trend_indicator.py +85 -0
  175. backtrader/indicators/contrib/candle_stop_color.py +46 -0
  176. backtrader/indicators/contrib/candles_x_smoothed_indicator.py +69 -0
  177. backtrader/indicators/contrib/candlesticks_bw.py +45 -0
  178. backtrader/indicators/contrib/caudate_x_period_candle_color.py +56 -0
  179. backtrader/indicators/contrib/cci_histogram_indicator.py +53 -0
  180. backtrader/indicators/contrib/cci_woodies_indicator.py +80 -0
  181. backtrader/indicators/contrib/center_of_gravity_candle_indicator.py +83 -0
  182. backtrader/indicators/contrib/center_of_gravity_indicator.py +70 -0
  183. backtrader/indicators/contrib/cg_oscillator.py +40 -0
  184. backtrader/indicators/contrib/close_line_cci.py +38 -0
  185. backtrader/indicators/contrib/close_price_fractals.py +47 -0
  186. backtrader/indicators/contrib/color3rd_gen_xma_indicator.py +122 -0
  187. backtrader/indicators/contrib/color_bb_candles_indicator.py +108 -0
  188. backtrader/indicators/contrib/color_coppock_indicator.py +157 -0
  189. backtrader/indicators/contrib/color_hma.py +71 -0
  190. backtrader/indicators/contrib/color_j_variation_indicator.py +53 -0
  191. backtrader/indicators/contrib/color_metro_de_marker_indicator.py +78 -0
  192. backtrader/indicators/contrib/color_metro_stochastic_indicator.py +93 -0
  193. backtrader/indicators/contrib/color_metro_wpr_indicator.py +85 -0
  194. backtrader/indicators/contrib/color_schaff_de_marker_trend_cycle.py +92 -0
  195. backtrader/indicators/contrib/color_schaff_trend_cycle_indicator.py +203 -0
  196. backtrader/indicators/contrib/color_step_xccx_indicator.py +193 -0
  197. backtrader/indicators/contrib/color_x2_ma.py +49 -0
  198. backtrader/indicators/contrib/color_x_derivative.py +63 -0
  199. backtrader/indicators/contrib/color_zerolag_de_marker.py +84 -0
  200. backtrader/indicators/contrib/corrected_average_indicator.py +127 -0
  201. backtrader/indicators/contrib/darvas_boxes_system.py +73 -0
  202. backtrader/indicators/contrib/dema_range_channel_color.py +42 -0
  203. backtrader/indicators/contrib/derivative_indicator.py +95 -0
  204. backtrader/indicators/contrib/digital_ft01_indicator.py +112 -0
  205. backtrader/indicators/contrib/digital_macd.py +200 -0
  206. backtrader/indicators/contrib/donchian_channels_system.py +45 -0
  207. backtrader/indicators/contrib/dots_indicator.py +93 -0
  208. backtrader/indicators/contrib/ef_distance_indicator.py +82 -0
  209. backtrader/indicators/contrib/ema_rsi_va.py +80 -0
  210. backtrader/indicators/contrib/envelopes_jp_alonso.py +32 -0
  211. backtrader/indicators/contrib/f2a_ao_indicator.py +120 -0
  212. backtrader/indicators/contrib/fatl_filter.py +179 -0
  213. backtrader/indicators/contrib/fibo_candles_indicator.py +78 -0
  214. backtrader/indicators/contrib/fine_tuning_ma.py +100 -0
  215. backtrader/indicators/contrib/fisher_org_v1.py +102 -0
  216. backtrader/indicators/contrib/fisher_org_v1_sign.py +118 -0
  217. backtrader/indicators/contrib/force_index_ema.py +96 -0
  218. backtrader/indicators/contrib/force_index_ema_2.py +27 -0
  219. backtrader/indicators/contrib/forecast_oscilator.py +145 -0
  220. backtrader/indicators/contrib/fractal_amambk.py +81 -0
  221. backtrader/indicators/contrib/frama_series.py +84 -0
  222. backtrader/indicators/contrib/frasm_av2_indicator.py +104 -0
  223. backtrader/indicators/contrib/go_indicator.py +93 -0
  224. backtrader/indicators/contrib/hlr_indicator.py +95 -0
  225. backtrader/indicators/contrib/hma.py +50 -0
  226. backtrader/indicators/contrib/i4_drfv2.py +34 -0
  227. backtrader/indicators/contrib/i4_drfv3.py +38 -0
  228. backtrader/indicators/contrib/i_anch_mom_indicator.py +72 -0
  229. backtrader/indicators/contrib/i_de_marker_sign_indicator.py +64 -0
  230. backtrader/indicators/contrib/i_gap_indicator.py +45 -0
  231. backtrader/indicators/contrib/i_stoch_komposter_indicator.py +77 -0
  232. backtrader/indicators/contrib/i_trend_indicator.py +125 -0
  233. backtrader/indicators/contrib/iamma_indicator.py +39 -0
  234. backtrader/indicators/contrib/indexed_moving_average.py +33 -0
  235. backtrader/indicators/contrib/instantaneous_trend_filter_indicator.py +51 -0
  236. backtrader/indicators/contrib/inverse_reaction_indicator.py +41 -0
  237. backtrader/indicators/contrib/irsi_sign_indicator.py +95 -0
  238. backtrader/indicators/contrib/iwpr_sign_indicator.py +59 -0
  239. backtrader/indicators/contrib/j_brain_trend1_sig_indicator.py +233 -0
  240. backtrader/indicators/contrib/j_tpo_proxy.py +32 -0
  241. backtrader/indicators/contrib/jma_slope_indicator.py +73 -0
  242. backtrader/indicators/contrib/kalman_filter_indicator.py +119 -0
  243. backtrader/indicators/contrib/kalman_filter_line.py +127 -0
  244. backtrader/indicators/contrib/kama_indicator.py +150 -0
  245. backtrader/indicators/contrib/karacatica_indicator.py +99 -0
  246. backtrader/indicators/contrib/kdj_indicator.py +59 -0
  247. backtrader/indicators/contrib/kwan_ccc_indicator.py +195 -0
  248. backtrader/indicators/contrib/kwan_nrp_indicator.py +113 -0
  249. backtrader/indicators/contrib/kwan_rdp_indicator.py +192 -0
  250. backtrader/indicators/contrib/laguerre_adx_indicator.py +85 -0
  251. backtrader/indicators/contrib/laguerre_filter_indicator.py +66 -0
  252. backtrader/indicators/contrib/laguerre_plus_di_proxy.py +57 -0
  253. backtrader/indicators/contrib/laguerre_roc_indicator.py +81 -0
  254. backtrader/indicators/contrib/le_man_signal_indicator.py +63 -0
  255. backtrader/indicators/contrib/linear_reg_slope_v2_indicator.py +136 -0
  256. backtrader/indicators/contrib/loco_indicator.py +88 -0
  257. backtrader/indicators/contrib/lrma_indicator.py +185 -0
  258. backtrader/indicators/contrib/lsma_angle_indicator.py +106 -0
  259. backtrader/indicators/contrib/ma_rounding_channel_indicator.py +149 -0
  260. backtrader/indicators/contrib/macd2_indicator.py +61 -0
  261. backtrader/indicators/contrib/macd_candle_indicator.py +80 -0
  262. backtrader/indicators/contrib/malr_indicator.py +77 -0
  263. backtrader/indicators/contrib/momentum_candle_sign_indicator.py +51 -0
  264. backtrader/indicators/contrib/moving_average_fn_indicator.py +139 -0
  265. backtrader/indicators/contrib/mt5_stochastic_close_close.py +57 -0
  266. backtrader/indicators/contrib/muv_nor_diff_cloud_indicator.py +107 -0
  267. backtrader/indicators/contrib/non_lag_dot_indicator.py +124 -0
  268. backtrader/indicators/contrib/nrtr_extr_indicator.py +95 -0
  269. backtrader/indicators/contrib/nrtr_indicator.py +95 -0
  270. backtrader/indicators/contrib/p_channel_system.py +40 -0
  271. backtrader/indicators/contrib/percent_envelope.py +37 -0
  272. backtrader/indicators/contrib/percentage_crossover_channel.py +47 -0
  273. backtrader/indicators/contrib/pivot_zig_zag_proxy.py +47 -0
  274. backtrader/indicators/contrib/price_channel_stop_indicator.py +104 -0
  275. backtrader/indicators/contrib/price_extreme_channel.py +35 -0
  276. backtrader/indicators/contrib/qqe_cloud_indicator.py +129 -0
  277. backtrader/indicators/contrib/ravi_indicator.py +40 -0
  278. backtrader/indicators/contrib/raw_close_close_stochastic.py +74 -0
  279. backtrader/indicators/contrib/rd_trend_trigger_indicator.py +51 -0
  280. backtrader/indicators/contrib/renko_level.py +85 -0
  281. backtrader/indicators/contrib/renko_line_break.py +91 -0
  282. backtrader/indicators/contrib/rftl_indicator.py +41 -0
  283. backtrader/indicators/contrib/rkd_indicator.py +53 -0
  284. backtrader/indicators/contrib/roc2_vg_indicator.py +68 -0
  285. backtrader/indicators/contrib/rsi_histogram_indicator.py +43 -0
  286. backtrader/indicators/contrib/rsi_slowdown.py +57 -0
  287. backtrader/indicators/contrib/rsioma_v2.py +41 -0
  288. backtrader/indicators/contrib/rvi_histogram_indicator.py +107 -0
  289. backtrader/indicators/contrib/safe_adx.py +89 -0
  290. backtrader/indicators/contrib/shared_strategy_indicators.py +1651 -0
  291. backtrader/indicators/contrib/sidus_indicator.py +105 -0
  292. backtrader/indicators/contrib/silver_trend_indicator.py +79 -0
  293. backtrader/indicators/contrib/sliding_range_color.py +56 -0
  294. backtrader/indicators/contrib/slow_stoch.py +42 -0
  295. backtrader/indicators/contrib/smoothed_adx_indicator.py +86 -0
  296. backtrader/indicators/contrib/smoothed_rsi.py +31 -0
  297. backtrader/indicators/contrib/spearman_rank_correlation_histogram.py +60 -0
  298. backtrader/indicators/contrib/stalin_indicator.py +152 -0
  299. backtrader/indicators/contrib/starter_laguerre_filter.py +62 -0
  300. backtrader/indicators/contrib/step_manrtr_indicator.py +137 -0
  301. backtrader/indicators/contrib/stochastic_histogram_indicator.py +143 -0
  302. backtrader/indicators/contrib/t3_alarm_indicator.py +125 -0
  303. backtrader/indicators/contrib/t3_average.py +76 -0
  304. backtrader/indicators/contrib/t3_indicator.py +40 -0
  305. backtrader/indicators/contrib/the20s_v020_signal.py +93 -0
  306. backtrader/indicators/contrib/three_candles_indicator.py +70 -0
  307. backtrader/indicators/contrib/three_line_break_indicator.py +64 -0
  308. backtrader/indicators/contrib/time_line.py +57 -0
  309. backtrader/indicators/contrib/trading_channel_index_proxy.py +48 -0
  310. backtrader/indicators/contrib/trend_arrows_indicator.py +109 -0
  311. backtrader/indicators/contrib/trend_continuation_indicator.py +127 -0
  312. backtrader/indicators/contrib/trend_intensity_index_proxy.py +51 -0
  313. backtrader/indicators/contrib/trend_manager_indicator.py +39 -0
  314. backtrader/indicators/contrib/tri_x_candle_indicator.py +51 -0
  315. backtrader/indicators/contrib/trigger_line.py +66 -0
  316. backtrader/indicators/contrib/triple_ema_rate.py +34 -0
  317. backtrader/indicators/contrib/trvi_indicator.py +194 -0
  318. backtrader/indicators/contrib/two_pb_ideal_xosma_indicator.py +127 -0
  319. backtrader/indicators/contrib/ultra_absolutely_no_lag_lwma_color.py +92 -0
  320. backtrader/indicators/contrib/ultra_wpr_indicator.py +173 -0
  321. backtrader/indicators/contrib/up_down_candle_strength.py +68 -0
  322. backtrader/indicators/contrib/vinin_i_trend_indicator.py +139 -0
  323. backtrader/indicators/contrib/volume_weighted_ma_indicator.py +78 -0
  324. backtrader/indicators/contrib/volume_weighted_ma_st_dev_indicator.py +111 -0
  325. backtrader/indicators/contrib/vwap_close_indicator.py +65 -0
  326. backtrader/indicators/contrib/vwma_candle.py +57 -0
  327. backtrader/indicators/contrib/vwma_digit_system.py +70 -0
  328. backtrader/indicators/contrib/wami.py +43 -0
  329. backtrader/indicators/contrib/wprsi_signal_indicator.py +105 -0
  330. backtrader/indicators/contrib/x_de_marker_histogram_vol_direct_indicator.py +145 -0
  331. backtrader/indicators/contrib/x_fisher_indicator.py +64 -0
  332. backtrader/indicators/contrib/xcci_histogram_vol_direct_indicator.py +56 -0
  333. backtrader/indicators/contrib/xcci_histogram_vol_indicator.py +85 -0
  334. backtrader/indicators/contrib/xma_ichimoku.py +163 -0
  335. backtrader/indicators/contrib/xma_ishimoku_channel_indicator.py +65 -0
  336. backtrader/indicators/contrib/xma_ishimoku_line.py +68 -0
  337. backtrader/indicators/contrib/xma_range_bands_indicator.py +107 -0
  338. backtrader/indicators/contrib/xmacd_indicator.py +70 -0
  339. backtrader/indicators/contrib/xrsi_de_marker_histogram.py +67 -0
  340. backtrader/indicators/contrib/xrsi_histogram_vol_direct_indicator.py +52 -0
  341. backtrader/indicators/contrib/xrsi_histogram_vol_indicator.py +81 -0
  342. backtrader/indicators/contrib/xrvi_indicator.py +130 -0
  343. backtrader/indicators/contrib/zero_lag_macd.py +36 -0
  344. backtrader/indicators/contrib/zig_zag_recent_pivot_signal.py +90 -0
  345. backtrader/indicators/contrib/zpf_indicator.py +115 -0
  346. backtrader/indicators/crossover.py +337 -0
  347. backtrader/indicators/dema.py +175 -0
  348. backtrader/indicators/demarker.py +270 -0
  349. backtrader/indicators/deviation.py +284 -0
  350. backtrader/indicators/directionalmove.py +1071 -0
  351. backtrader/indicators/dma.py +112 -0
  352. backtrader/indicators/dpo.py +96 -0
  353. backtrader/indicators/dv2.py +56 -0
  354. backtrader/indicators/ema.py +145 -0
  355. backtrader/indicators/envelope.py +475 -0
  356. backtrader/indicators/hadelta.py +198 -0
  357. backtrader/indicators/heikinashi.py +153 -0
  358. backtrader/indicators/hma.py +153 -0
  359. backtrader/indicators/hurst.py +151 -0
  360. backtrader/indicators/ichimoku.py +267 -0
  361. backtrader/indicators/kama.py +181 -0
  362. backtrader/indicators/kst.py +159 -0
  363. backtrader/indicators/lrsi.py +125 -0
  364. backtrader/indicators/mabase.py +147 -0
  365. backtrader/indicators/macd.py +322 -0
  366. backtrader/indicators/momentum.py +267 -0
  367. backtrader/indicators/moneyflow.py +237 -0
  368. backtrader/indicators/mt5atr.py +124 -0
  369. backtrader/indicators/myind.py +179 -0
  370. backtrader/indicators/obv.py +94 -0
  371. backtrader/indicators/ols.py +265 -0
  372. backtrader/indicators/oscillator.py +161 -0
  373. backtrader/indicators/percentchange.py +83 -0
  374. backtrader/indicators/percentrank.py +46 -0
  375. backtrader/indicators/pivotpoint.py +469 -0
  376. backtrader/indicators/prettygoodoscillator.py +113 -0
  377. backtrader/indicators/priceops_ext.py +123 -0
  378. backtrader/indicators/priceoscillator.py +262 -0
  379. backtrader/indicators/psar.py +212 -0
  380. backtrader/indicators/rmi.py +69 -0
  381. backtrader/indicators/rsi.py +440 -0
  382. backtrader/indicators/sma.py +141 -0
  383. backtrader/indicators/smma.py +116 -0
  384. backtrader/indicators/spread.py +54 -0
  385. backtrader/indicators/stochastic.py +263 -0
  386. backtrader/indicators/supertrend.py +436 -0
  387. backtrader/indicators/trend_ext.py +105 -0
  388. backtrader/indicators/trix.py +202 -0
  389. backtrader/indicators/tsi.py +155 -0
  390. backtrader/indicators/ultimateoscillator.py +158 -0
  391. backtrader/indicators/vortex.py +62 -0
  392. backtrader/indicators/williams.py +194 -0
  393. backtrader/indicators/wma.py +103 -0
  394. backtrader/indicators/zlema.py +135 -0
  395. backtrader/indicators/zlind.py +104 -0
  396. backtrader/linebuffer.py +3155 -0
  397. backtrader/lineiterator.py +2911 -0
  398. backtrader/lineroot.py +1106 -0
  399. backtrader/lineseries.py +2559 -0
  400. backtrader/live_trading/__init__.py +31 -0
  401. backtrader/live_trading/interface.py +404 -0
  402. backtrader/mathsupport.py +94 -0
  403. backtrader/metabase.py +1804 -0
  404. backtrader/mixins/__init__.py +21 -0
  405. backtrader/mixins/singleton.py +118 -0
  406. backtrader/observer.py +106 -0
  407. backtrader/observers/__init__.py +45 -0
  408. backtrader/observers/benchmark.py +126 -0
  409. backtrader/observers/broker.py +184 -0
  410. backtrader/observers/buysell.py +144 -0
  411. backtrader/observers/drawdown.py +161 -0
  412. backtrader/observers/logreturns.py +113 -0
  413. backtrader/observers/timereturn.py +86 -0
  414. backtrader/observers/trade_logger.py +2972 -0
  415. backtrader/observers/tradelogger.py +6 -0
  416. backtrader/observers/trades.py +258 -0
  417. backtrader/order.py +1114 -0
  418. backtrader/parameters.py +2345 -0
  419. backtrader/plot/__init__.py +54 -0
  420. backtrader/plot/finance.py +1022 -0
  421. backtrader/plot/formatters.py +200 -0
  422. backtrader/plot/locator.py +353 -0
  423. backtrader/plot/multicursor.py +495 -0
  424. backtrader/plot/plot.py +2500 -0
  425. backtrader/plot/plot_plotly.py +1351 -0
  426. backtrader/plot/scheme.py +253 -0
  427. backtrader/plot/utils.py +104 -0
  428. backtrader/position.py +290 -0
  429. backtrader/position_modes.py +132 -0
  430. backtrader/profiles.py +254 -0
  431. backtrader/reports/__init__.py +39 -0
  432. backtrader/reports/charts.py +371 -0
  433. backtrader/reports/performance.py +620 -0
  434. backtrader/reports/reporter.py +660 -0
  435. backtrader/resamplerfilter.py +1001 -0
  436. backtrader/signal.py +118 -0
  437. backtrader/signals/__init__.py +17 -0
  438. backtrader/sizer.py +114 -0
  439. backtrader/sizers/__init__.py +26 -0
  440. backtrader/sizers/fixedsize.py +161 -0
  441. backtrader/sizers/percents_sizer.py +119 -0
  442. backtrader/store.py +221 -0
  443. backtrader/stores/__init__.py +33 -0
  444. backtrader/stores/btapistore.py +15506 -0
  445. backtrader/stores/livestore.py +137 -0
  446. backtrader/stores/vchartfile.py +96 -0
  447. backtrader/strategy.py +3655 -0
  448. backtrader/talib.py +280 -0
  449. backtrader/test_helpers.py +96 -0
  450. backtrader/timer.py +358 -0
  451. backtrader/trade.py +442 -0
  452. backtrader/tradingcal.py +361 -0
  453. backtrader/utils/__init__.py +68 -0
  454. backtrader/utils/autodict.py +251 -0
  455. backtrader/utils/date.py +71 -0
  456. backtrader/utils/dateintern.py +509 -0
  457. backtrader/utils/flushfile.py +94 -0
  458. backtrader/utils/fractal.py +101 -0
  459. backtrader/utils/get_metrics.py +101 -0
  460. backtrader/utils/load_data.py +209 -0
  461. backtrader/utils/log_message.py +998 -0
  462. backtrader/utils/ordereddefaultdict.py +75 -0
  463. backtrader/utils/py3.py +296 -0
  464. backtrader/version.py +21 -0
  465. backtrader/writer.py +372 -0
@@ -0,0 +1,572 @@
1
+ """Order-matching core for the tick-level broker.
2
+
3
+ Defines the fill/match data structures (:class:`FillReport`, :class:`MatchResult`)
4
+ and the matching engine that turns tick/depth events plus pending orders into
5
+ fills, applying the configured exchange and queue models.
6
+ """
7
+
8
+ from dataclasses import dataclass, field
9
+
10
+ from backtrader.order import Order
11
+
12
+ from .exchange import FillRole
13
+
14
+
15
+ @dataclass
16
+ class FillReport:
17
+ """Single execution report produced by the matching engine.
18
+
19
+ Attributes:
20
+ order: The :class:`backtrader.order.Order` instance that was
21
+ filled (kept by reference so callers can correlate the fill
22
+ back to the originating strategy order).
23
+ fill_price: Trade price at which this fill leg executed.
24
+ fill_size: Signed quantity executed on this fill leg. Always
25
+ positive; the side (buy/sell) is carried by ``order``.
26
+ role: Whether this fill came from a taker or maker execution.
27
+ ``"taker"`` for liquidity-taking orders and ``"maker"`` for
28
+ passive orders that were resting in the book.
29
+ timestamp: Simulation timestamp at which the fill happened
30
+ (typically the upstream exchange or local-receive timestamp).
31
+ source: Origin tag of the event that triggered the fill — usually
32
+ ``"tick"`` for trade prints or ``"orderbook_depth"`` for
33
+ top-of-book updates.
34
+ """
35
+
36
+ order: object
37
+ fill_price: float
38
+ fill_size: float
39
+ role: str = "taker"
40
+ timestamp: float = 0.0
41
+ source: str = "tick"
42
+
43
+
44
+ @dataclass
45
+ class MatchResult:
46
+ """Outcome of an operation against the matching engine.
47
+
48
+ Attributes:
49
+ action: One of ``"ACCEPTED"``, ``"REJECT"``, ``"MODIFIED"``,
50
+ ``"CANCELED"``, ``"FILL"`` or ``"PENDING"`` describing what
51
+ the matching engine did with the request/event.
52
+ fills: List of :class:`FillReport` entries produced by this
53
+ operation. Empty when no fill happened (e.g. an order was
54
+ accepted but no market data was available yet).
55
+ reject_reason: Human-readable explanation populated when
56
+ ``action == "REJECT"``. Empty otherwise.
57
+ """
58
+
59
+ action: str
60
+ fills: list = field(default_factory=list)
61
+ reject_reason: str = ""
62
+
63
+
64
+ @dataclass
65
+ class CancelResult:
66
+ """Outcome of an order cancellation request.
67
+
68
+ Attributes:
69
+ success: ``True`` if the order was found and removed from the
70
+ matching engine's pending book; ``False`` otherwise.
71
+ reason: Human-readable explanation populated when ``success`` is
72
+ ``False`` (currently ``"ORDER_NOT_FOUND"`` when the order
73
+ is not in the pending set). Empty for successful cancels.
74
+ """
75
+
76
+ success: bool
77
+ reason: str = ""
78
+
79
+
80
+ class MatchingCore:
81
+ """Tick/depth matching engine for the HFT broker.
82
+
83
+ The matching core owns the pending-order book (per symbol) and
84
+ reacts to incoming tick and order-book events by matching them
85
+ against pending orders. The actual fill logic (price-time priority,
86
+ slippage, queue position, etc.) is delegated to two pluggable
87
+ helpers:
88
+
89
+ * ``latency_engine`` — when provided, decides when a freshly
90
+ submitted order becomes "visible" to the matching engine. While
91
+ invisible the order is parked in the latency engine rather than
92
+ in the core's pending buckets, and :meth:`activate_orders`
93
+ promotes it once it becomes visible.
94
+ * ``exchange_model`` — when provided, decides whether an incoming
95
+ tick or order-book event actually triggers a fill for a pending
96
+ order. The default internal matcher (``_match_tick_order`` /
97
+ ``_match_orderbook_order``) implements a simple limit/market
98
+ price-time matching, which is bypassed when the exchange model
99
+ returns ``"FILL"`` or ``"REJECT"`` for the order.
100
+
101
+ Attributes:
102
+ _latency: Pluggable latency engine (``None`` to skip latency).
103
+ _exchange_model: Pluggable exchange model (``None`` to use the
104
+ built-in matcher).
105
+ _pending_by_symbol: Mapping ``symbol -> list[Order]`` of orders
106
+ that are currently sitting in the matching engine's book.
107
+ _order_to_symbol: Mapping ``id(order) -> symbol`` used to look
108
+ up the symbol of an order that the caller hands back via
109
+ :meth:`cancel_order` / :meth:`remove_order` (the order
110
+ itself does not always expose its symbol).
111
+ """
112
+
113
+ def __init__(self, latency_engine=None, exchange_model=None):
114
+ """Initialize the matching core.
115
+
116
+ Args:
117
+ latency_engine: Optional pluggable latency engine. When
118
+ supplied, freshly submitted orders are routed through it
119
+ and only become visible to the matcher after the
120
+ configured entry latency elapses (see
121
+ :meth:`activate_orders`).
122
+ exchange_model: Optional pluggable exchange model. When
123
+ supplied, ``on_tick`` and ``on_orderbook`` delegate the
124
+ fill decision to ``exchange_model.on_trade`` /
125
+ ``exchange_model.on_new_order`` instead of using the
126
+ built-in limit/market matcher.
127
+ """
128
+ self._latency = latency_engine
129
+ self._exchange_model = exchange_model
130
+ self._pending_by_symbol = {}
131
+ self._order_to_symbol = {}
132
+
133
+ def _get_symbol(self, order):
134
+ data = getattr(order, "data", None)
135
+ if data is None:
136
+ return ""
137
+ return getattr(data, "_name", None) or getattr(data, "symbol", str(data))
138
+
139
+ def _bucket(self, symbol):
140
+ if symbol not in self._pending_by_symbol:
141
+ self._pending_by_symbol[symbol] = []
142
+ return self._pending_by_symbol[symbol]
143
+
144
+ def _add_pending(self, order, symbol=None):
145
+ symbol = symbol or self._get_symbol(order)
146
+ bucket = self._bucket(symbol)
147
+ if order not in bucket:
148
+ bucket.append(order)
149
+ self._order_to_symbol[id(order)] = symbol
150
+
151
+ def submit_order(self, order, current_ts=0.0):
152
+ """Submit a new order to the matching engine.
153
+
154
+ If a latency engine is configured the order is first routed
155
+ through it; orders that have not yet become visible (latency
156
+ still pending) are kept inside the latency engine and will
157
+ be promoted to the matching book later via
158
+ :meth:`activate_orders`. Orders that are immediately visible —
159
+ or for which no latency engine is configured — are appended
160
+ to the per-symbol pending bucket.
161
+
162
+ Args:
163
+ order: Order object to submit. ``order.data`` is consulted
164
+ to derive its trading symbol.
165
+ current_ts: Simulation timestamp at which the submission
166
+ happens. Forwarded to ``latency_engine.delay_order``
167
+ when a latency engine is configured.
168
+
169
+ Returns:
170
+ MatchResult: ``MatchResult(action="ACCEPTED")``. The result
171
+ is always ``ACCEPTED`` — rejections are signalled by the
172
+ caller (e.g. broker) after inspecting fill notifications.
173
+ """
174
+ symbol = self._get_symbol(order)
175
+ if self._latency is not None:
176
+ visible_ts = self._latency.delay_order(order, current_ts, symbol)
177
+ if visible_ts is not None:
178
+ self._order_to_symbol[id(order)] = symbol
179
+ return MatchResult(action="ACCEPTED")
180
+ self._add_pending(order, symbol)
181
+ return MatchResult(action="ACCEPTED")
182
+
183
+ def modify_order(self, order, replacement_order, current_ts=0.0):
184
+ """Replace ``order`` with ``replacement_order``.
185
+
186
+ Modification is implemented as "cancel + resubmit": the original
187
+ order is removed from the matching book and, if a replacement
188
+ was supplied, it is re-submitted using the same
189
+ :meth:`submit_order` path so that latency-engine rules apply
190
+ uniformly.
191
+
192
+ Args:
193
+ order: Existing order to replace. Looked up in the pending
194
+ book (and the latency engine when relevant).
195
+ replacement_order: New order to submit in place of
196
+ ``order``. ``None`` means "cancel only" — the operation
197
+ succeeds but no replacement is queued.
198
+ current_ts: Simulation timestamp at which the modification
199
+ is being applied. Forwarded to :meth:`submit_order` for
200
+ the replacement.
201
+
202
+ Returns:
203
+ MatchResult: ``MODIFIED`` when the original was successfully
204
+ cancelled and the replacement was queued, ``CANCELED`` when
205
+ no replacement was supplied, ``REJECT`` if the original
206
+ could not be found in either the pending book or the
207
+ latency engine.
208
+ """
209
+ cancel_result = self.cancel_order(order)
210
+ if not cancel_result.success:
211
+ return MatchResult(action="REJECT", reject_reason=cancel_result.reason)
212
+ if replacement_order is None:
213
+ return MatchResult(action="CANCELED")
214
+ self.submit_order(replacement_order, current_ts=current_ts)
215
+ return MatchResult(action="MODIFIED")
216
+
217
+ def activate_orders(self, current_ts):
218
+ """Promote orders whose entry latency has elapsed into the matching book.
219
+
220
+ For every order that the latency engine reports as having
221
+ become visible at ``current_ts``, the order is moved into the
222
+ per-symbol pending bucket and returned in the activation list
223
+ so that the caller (typically the broker) can run post-activation
224
+ hooks (queue-position computation, etc.).
225
+
226
+ Args:
227
+ current_ts: Current simulation timestamp. Compared against
228
+ the visibility timestamp returned by the latency
229
+ engine.
230
+
231
+ Returns:
232
+ list[Order]: Orders that were activated at ``current_ts``.
233
+ Empty when no latency engine is configured or when nothing
234
+ has yet become visible.
235
+ """
236
+ if self._latency is None:
237
+ return []
238
+ activated = []
239
+ for order, symbol in self._latency.get_visible_orders(current_ts):
240
+ self._add_pending(order, symbol)
241
+ activated.append(order)
242
+ return activated
243
+
244
+ def cancel_order(self, order):
245
+ """Remove ``order`` from the matching engine (pending book or latency engine).
246
+
247
+ The method first looks up the order's symbol via the
248
+ ``_order_to_symbol`` cache (falling back to deriving it from
249
+ ``order.data``), then attempts to remove it from the per-symbol
250
+ pending bucket. If the order is not in the pending bucket but a
251
+ latency engine is configured, the latency engine is asked to
252
+ cancel it instead — useful for orders that have been submitted
253
+ but not yet become visible.
254
+
255
+ Args:
256
+ order: Order to cancel. Must be the same object that was
257
+ passed to :meth:`submit_order` / :meth:`modify_order`,
258
+ because the engine identifies orders by ``id(order)``.
259
+
260
+ Returns:
261
+ CancelResult: ``CancelResult(success=True)`` when the order
262
+ was removed from either the pending book or the latency
263
+ engine; ``CancelResult(success=False,
264
+ reason="ORDER_NOT_FOUND")`` otherwise.
265
+ """
266
+ symbol = self._order_to_symbol.get(id(order), self._get_symbol(order))
267
+ bucket = self._pending_by_symbol.get(symbol, [])
268
+ try:
269
+ bucket.remove(order)
270
+ self._order_to_symbol.pop(id(order), None)
271
+ if not bucket and symbol in self._pending_by_symbol:
272
+ del self._pending_by_symbol[symbol]
273
+ return CancelResult(success=True)
274
+ except ValueError:
275
+ if self._latency is not None:
276
+ self._latency.cancel_order(order)
277
+ self._order_to_symbol.pop(id(order), None)
278
+ return CancelResult(success=True)
279
+ return CancelResult(success=False, reason="ORDER_NOT_FOUND")
280
+
281
+ def remove_order(self, order):
282
+ """Silently drop ``order`` from the matching book without raising.
283
+
284
+ Used by the broker when an order transitions to a terminal state
285
+ (rejected, expired, margin-called) and the matching engine
286
+ should forget about it. Unlike :meth:`cancel_order`, this method
287
+ never returns a result and never raises — the absence of the
288
+ order is not an error condition.
289
+
290
+ Args:
291
+ order: Order to forget. Looked up by ``id(order)`` first and
292
+ falls back to deriving the symbol from ``order.data``.
293
+ """
294
+ symbol = self._order_to_symbol.pop(id(order), self._get_symbol(order))
295
+ bucket = self._pending_by_symbol.get(symbol, [])
296
+ try:
297
+ bucket.remove(order)
298
+ except ValueError:
299
+ return
300
+ if not bucket and symbol in self._pending_by_symbol:
301
+ del self._pending_by_symbol[symbol]
302
+
303
+ def pending_for_symbol(self, symbol):
304
+ """Return a copy of the pending book for ``symbol``.
305
+
306
+ The returned list is a snapshot; mutating it does not affect
307
+ the engine's internal state.
308
+
309
+ Args:
310
+ symbol: Trading symbol to look up.
311
+
312
+ Returns:
313
+ list[Order]: Pending orders in arrival order for ``symbol``.
314
+ Empty list if the symbol has no pending orders.
315
+ """
316
+ return list(self._pending_by_symbol.get(symbol, []))
317
+
318
+ def pending_orders(self):
319
+ """Return a flat snapshot of every pending order across all symbols.
320
+
321
+ Returns:
322
+ list[Order]: Pending orders across all symbols, in an
323
+ unspecified but stable order (one bucket after another, in
324
+ ``_pending_by_symbol`` insertion order).
325
+ """
326
+ result = []
327
+ for bucket in self._pending_by_symbol.values():
328
+ result.extend(bucket)
329
+ return result
330
+
331
+ def on_tick(self, tick_event):
332
+ """Match a single trade tick against the pending book of its symbol.
333
+
334
+ When an exchange model is configured, its
335
+ ``on_trade(tick_event, pending_orders)`` is consulted first to
336
+ generate fills; when no exchange model is set, the built-in
337
+ limit/market matcher (:meth:`_match_tick_order`) is used
338
+ instead. Orders whose ``_fill_role`` is :data:`FillRole.MAKER`
339
+ are skipped from the built-in matcher because the exchange
340
+ model is expected to drive their lifecycle.
341
+
342
+ Args:
343
+ tick_event: Tick-like object exposing ``symbol``,
344
+ ``timestamp`` and ``price``. The exact type is not
345
+ enforced — the engine only relies on these three
346
+ attributes.
347
+
348
+ Returns:
349
+ MatchResult: ``MatchResult(action="FILL", fills=[...])`` if
350
+ at least one fill was produced; otherwise
351
+ ``MatchResult(action="PENDING", fills=[])``. The fills list
352
+ holds one :class:`FillReport` per matched order.
353
+ """
354
+ symbol = getattr(tick_event, "symbol", "")
355
+ fills = []
356
+ pending = list(self.pending_for_symbol(symbol))
357
+ if self._exchange_model is not None:
358
+ for order, price, size, role in self._exchange_model.on_trade(tick_event, pending):
359
+ fills.append(
360
+ self._build_fill(
361
+ order, price, size, tick_event.timestamp, source=role.value, role=role.value
362
+ )
363
+ )
364
+
365
+ for order in pending:
366
+ if (
367
+ self._exchange_model is not None
368
+ and getattr(order, "_fill_role", None) == FillRole.MAKER
369
+ ):
370
+ continue
371
+ result = self._match_tick_order(order, tick_event)
372
+ if result is None:
373
+ continue
374
+ price, size = result
375
+ fills.append(self._build_fill(order, price, size, tick_event.timestamp))
376
+
377
+ return MatchResult(action="FILL" if fills else "PENDING", fills=fills)
378
+
379
+ def on_orderbook(self, ob_event):
380
+ """Match a single order-book snapshot against the pending book of its symbol.
381
+
382
+ For each pending order of ``ob_event.symbol`` the method first
383
+ consults the configured exchange model (``on_new_order``). If
384
+ the model reports ``"REJECT"`` the engine short-circuits and
385
+ returns a :class:`MatchResult` with that reject reason; if it
386
+ reports ``"FILL"`` the aggregated fill price/size is recorded
387
+ and the loop continues with the next order. Otherwise the
388
+ built-in order-book matcher (:meth:`_match_orderbook_order`)
389
+ runs and may produce a fill.
390
+
391
+ Args:
392
+ ob_event: Order-book event exposing ``symbol``,
393
+ ``timestamp``, ``asks`` and ``bids``. ``asks``/``bids``
394
+ are expected to be sequences of ``(price, qty)`` tuples
395
+ sorted from best to worst.
396
+
397
+ Returns:
398
+ MatchResult: ``MatchResult(action="FILL", fills=[...])``
399
+ when at least one fill was produced;
400
+ ``MatchResult(action="REJECT", reject_reason=...)`` when
401
+ the exchange model rejected an order;
402
+ ``MatchResult(action="PENDING", fills=[])`` when no fill
403
+ happened. The ``"REJECT"`` path returns immediately, so any
404
+ remaining orders are not processed in the same call.
405
+ """
406
+ symbol = getattr(ob_event, "symbol", "")
407
+ fills = []
408
+ for order in list(self.pending_for_symbol(symbol)):
409
+ if self._exchange_model is not None and order.exectype in (Order.Market, Order.Limit):
410
+ exchange_result = self._exchange_model.on_new_order(order, ob_event)
411
+ if exchange_result.action == "REJECT":
412
+ return MatchResult(action="REJECT", reject_reason=exchange_result.reject_reason)
413
+ if exchange_result.action == "FILL":
414
+ price, size = self._aggregate_exchange_fills(exchange_result.fills)
415
+ if size > 0:
416
+ fills.append(
417
+ self._build_fill(
418
+ order, price, size, ob_event.timestamp, source="orderbook_depth"
419
+ )
420
+ )
421
+ continue
422
+ if getattr(order, "_fill_role", None) == FillRole.MAKER:
423
+ continue
424
+
425
+ result = self._match_orderbook_order(order, ob_event)
426
+ if result is None:
427
+ continue
428
+ price, size = result
429
+ fills.append(
430
+ self._build_fill(order, price, size, ob_event.timestamp, source="orderbook_depth")
431
+ )
432
+
433
+ return MatchResult(action="FILL" if fills else "PENDING", fills=fills)
434
+
435
+ def _build_fill(self, order, price, size, timestamp, source="tick", role="taker"):
436
+ return FillReport(
437
+ order=order,
438
+ fill_price=price,
439
+ fill_size=size,
440
+ role=role,
441
+ timestamp=timestamp,
442
+ source=source,
443
+ )
444
+
445
+ @staticmethod
446
+ def _remaining_size(order):
447
+ remaining = getattr(getattr(order, "executed", None), "remsize", None)
448
+ if remaining is None:
449
+ remaining = getattr(order, "size", 0.0)
450
+ if remaining is None:
451
+ remaining = 0.0
452
+ return abs(float(remaining))
453
+
454
+ @staticmethod
455
+ def _aggregate_exchange_fills(fills):
456
+ total_size = 0.0
457
+ total_value = 0.0
458
+ for price, size, _role in fills:
459
+ total_value += price * size
460
+ total_size += size
461
+ if total_size <= 0.0:
462
+ return (0.0, 0.0)
463
+ return (total_value / total_size, total_size)
464
+
465
+ def _match_tick_order(self, order, tick_event):
466
+ exectype = self._effective_exectype(order, tick_event.price)
467
+ size = self._remaining_size(order)
468
+ price = tick_event.price
469
+
470
+ if exectype == Order.Market:
471
+ return (price, size)
472
+
473
+ if exectype == Order.Limit:
474
+ limit_price = (
475
+ order.pricelimit
476
+ if getattr(order, "_stop_triggered", False) and order.exectype == Order.StopLimit
477
+ else order.price
478
+ )
479
+ if order.isbuy() and price <= limit_price:
480
+ return (min(price, limit_price), size)
481
+ if not order.isbuy() and price >= limit_price:
482
+ return (max(price, limit_price), size)
483
+ return None
484
+
485
+ def _match_orderbook_order(self, order, ob_event):
486
+ exectype = self._effective_exectype(order, self._trigger_reference_price(order, ob_event))
487
+ size = self._remaining_size(order)
488
+
489
+ if exectype == Order.Market:
490
+ if order.isbuy():
491
+ return self._match_buy_depth(ob_event.asks, size, None)
492
+ return self._match_sell_depth(ob_event.bids, size, None)
493
+
494
+ if exectype == Order.Limit:
495
+ limit_price = (
496
+ order.pricelimit
497
+ if getattr(order, "_stop_triggered", False) and order.exectype == Order.StopLimit
498
+ else order.price
499
+ )
500
+ if order.isbuy() and ob_event.asks and ob_event.asks[0][0] <= limit_price:
501
+ return self._match_buy_depth(ob_event.asks, size, limit_price)
502
+ if (not order.isbuy()) and ob_event.bids and ob_event.bids[0][0] >= limit_price:
503
+ return self._match_sell_depth(ob_event.bids, size, limit_price)
504
+ return None
505
+
506
+ def _effective_exectype(self, order, reference_price):
507
+ exectype = order.exectype
508
+ if exectype == Order.Stop:
509
+ if self._check_stop_trigger(order, reference_price):
510
+ return Order.Market
511
+ return None
512
+ if exectype == Order.StopLimit:
513
+ if self._check_stop_trigger(order, reference_price):
514
+ return Order.Limit
515
+ return None
516
+ return exectype
517
+
518
+ def _check_stop_trigger(self, order, reference_price):
519
+ if getattr(order, "_stop_triggered", False):
520
+ return True
521
+ stop_price = getattr(order, "price", None)
522
+ if stop_price is None or reference_price is None:
523
+ return False
524
+ if order.isbuy() and reference_price >= stop_price:
525
+ order._stop_triggered = True
526
+ return True
527
+ if (not order.isbuy()) and reference_price <= stop_price:
528
+ order._stop_triggered = True
529
+ return True
530
+ return False
531
+
532
+ @staticmethod
533
+ def _trigger_reference_price(order, ob_event):
534
+ if order.isbuy():
535
+ return ob_event.asks[0][0] if ob_event.asks else None
536
+ return ob_event.bids[0][0] if ob_event.bids else None
537
+
538
+ @staticmethod
539
+ def _match_buy_depth(asks, target_size, limit_price):
540
+ total_filled = 0.0
541
+ total_cost = 0.0
542
+ for price, qty in asks:
543
+ if limit_price is not None and price > limit_price:
544
+ break
545
+ fill = min(target_size - total_filled, qty)
546
+ if fill <= 0:
547
+ continue
548
+ total_cost += price * fill
549
+ total_filled += fill
550
+ if total_filled >= target_size:
551
+ break
552
+ if total_filled <= 0:
553
+ return None
554
+ return (total_cost / total_filled, total_filled)
555
+
556
+ @staticmethod
557
+ def _match_sell_depth(bids, target_size, limit_price):
558
+ total_filled = 0.0
559
+ total_value = 0.0
560
+ for price, qty in bids:
561
+ if limit_price is not None and price < limit_price:
562
+ break
563
+ fill = min(target_size - total_filled, qty)
564
+ if fill <= 0:
565
+ continue
566
+ total_value += price * fill
567
+ total_filled += fill
568
+ if total_filled >= target_size:
569
+ break
570
+ if total_filled <= 0:
571
+ return None
572
+ return (total_value / total_filled, total_filled)