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,186 @@
1
+ """Channel-to-LineSeries bridge for indicator compatibility.
2
+
3
+ ChannelBridge optionally bridges data from Channel events to LineSeries,
4
+ enabling the use of traditional backtrader indicators (SMA, RSI, etc.)
5
+ on tick-level data. This comes with a performance overhead warning.
6
+
7
+ Example::
8
+
9
+ bridge = ChannelBridge(tick_channel, fields=['price', 'volume'])
10
+ bridge.update(tick_event)
11
+ # Now bridge.lines.price[0] contains the latest tick price
12
+ """
13
+
14
+ from collections import deque
15
+
16
+ from ..utils.log_message import get_logger
17
+
18
+ logger = get_logger(__name__)
19
+
20
+ __all__ = ["ChannelBridge"]
21
+
22
+
23
+ class ChannelBridge:
24
+ """Bridge between DataChannel events and a simple line-like interface.
25
+
26
+ Buffers specified fields from channel events into deque-based lines
27
+ that can be accessed with [0], [-1] indexing. This is a lightweight
28
+ bridge - it does NOT create full LineSeries objects but provides
29
+ a compatible enough interface for simple indicator usage.
30
+
31
+ Note:
32
+ Using ChannelBridge adds overhead. Only use it when you need
33
+ indicators on channel data. For pure tick processing, use
34
+ channel events directly.
35
+
36
+ Args:
37
+ channel: The DataChannel to bridge from.
38
+ fields: List of field names to bridge (e.g., ['price', 'volume']).
39
+ maxlen: Maximum number of values to retain per line.
40
+
41
+ Example::
42
+
43
+ bridge = ChannelBridge(tick_ch, fields=['price', 'volume'])
44
+ bridge.update(tick_event)
45
+ print(bridge['price'][0]) # latest price
46
+ print(bridge['price'][-1]) # previous price
47
+ """
48
+
49
+ def __init__(self, channel, fields=None, maxlen=10000):
50
+ """Initialize the channel bridge.
51
+
52
+ Args:
53
+ channel: The DataChannel instance to bridge.
54
+ fields: Optional list of field names to extract.
55
+ maxlen: Maximum deque length for each field.
56
+ """
57
+ self.channel = channel
58
+ self._maxlen = maxlen
59
+ self._fields = fields or self._default_fields(channel)
60
+ self._lines: dict = {f: deque(maxlen=maxlen) for f in self._fields}
61
+ self._count = 0
62
+
63
+ def _default_fields(self, channel):
64
+ """Determine default fields based on channel type.
65
+
66
+ Args:
67
+ channel: The DataChannel instance to introspect.
68
+
69
+ Returns:
70
+ List of default field names for the channel type.
71
+ """
72
+ type_fields = {
73
+ "tick": ["price", "volume", "timestamp"],
74
+ "orderbook": ["timestamp"],
75
+ "funding": ["rate", "mark_price", "timestamp"],
76
+ "bar": ["open", "high", "low", "close", "volume", "timestamp"],
77
+ }
78
+ return type_fields.get(channel.channel_type, ["timestamp"])
79
+
80
+ def update(self, event):
81
+ """Update bridge lines with data from a new event.
82
+
83
+ Args:
84
+ event: An EventData instance whose fields are extracted.
85
+ """
86
+ for field in self._fields:
87
+ value = getattr(event, field, None)
88
+ if value is not None:
89
+ self._lines[field].append(value)
90
+ else:
91
+ self._lines[field].append(float("nan"))
92
+ self._count += 1
93
+
94
+ @property
95
+ def fields(self):
96
+ """List of bridged field names."""
97
+ return list(self._fields)
98
+
99
+ @property
100
+ def count(self):
101
+ """Number of events bridged."""
102
+ return self._count
103
+
104
+ def __getitem__(self, field):
105
+ """Get a line by field name.
106
+
107
+ Args:
108
+ field: Field name string.
109
+
110
+ Returns:
111
+ _BridgeLine accessor for the field.
112
+ """
113
+ if field not in self._lines:
114
+ raise KeyError(f"Field '{field}' not bridged. Available: {list(self._lines.keys())}")
115
+ return _BridgeLine(self._lines[field])
116
+
117
+ def __len__(self):
118
+ """Number of data points in the bridge."""
119
+ if self._lines:
120
+ return len(next(iter(self._lines.values())))
121
+ return 0
122
+
123
+ def __repr__(self):
124
+ """Return a string representation of the bridge.
125
+
126
+ Returns:
127
+ str: Representation showing channel, fields, and event count.
128
+ """
129
+ return (
130
+ f"ChannelBridge(channel={self.channel!r}, fields={self._fields}, count={self._count})"
131
+ )
132
+
133
+
134
+ class _BridgeLine:
135
+ """Accessor for a single bridged line with [-n] indexing.
136
+
137
+ Supports [0] for latest, [-1] for previous, etc. Mimics
138
+ backtrader's line indexing convention.
139
+ """
140
+
141
+ def __init__(self, data):
142
+ """Initialize the bridge line accessor.
143
+
144
+ Args:
145
+ data: Deque containing the historical values for this line.
146
+ """
147
+ self._data = data
148
+
149
+ def __getitem__(self, index):
150
+ """Access line values with backtrader-style indexing.
151
+
152
+ Supports backtrader's line indexing convention where:
153
+ [0] = latest value (last element)
154
+ [-1] = previous value (second to last)
155
+ [-2] = two values back
156
+ [n] = future offset from current (only 0 supported)
157
+
158
+ Args:
159
+ index: Integer index (0 for latest, negative for historical).
160
+
161
+ Returns:
162
+ float: The value at the specified index, or NaN if out of bounds.
163
+ """
164
+ if not self._data:
165
+ return float("nan")
166
+ if index == 0:
167
+ return self._data[-1]
168
+ if index < 0:
169
+ # -1 = previous, -2 = two back, etc.
170
+ pos = len(self._data) + index - 1
171
+ if 0 <= pos < len(self._data):
172
+ return self._data[pos]
173
+ return float("nan")
174
+ return float("nan")
175
+
176
+ def __len__(self):
177
+ """Return the number of data points in the line."""
178
+ return len(self._data)
179
+
180
+ def __repr__(self):
181
+ """Return a string representation of the bridge line.
182
+
183
+ Returns:
184
+ str: Representation showing data length.
185
+ """
186
+ return f"_BridgeLine(length={len(self._data)})"
@@ -0,0 +1,248 @@
1
+ """Funding rate data channel for perpetual contract funding rates.
2
+
3
+ Provides FundingRateChannel for loading, validating, and buffering
4
+ funding rate data from CSV/JSONL files or other sources.
5
+
6
+ Example:
7
+ Loading funding rate data from CSV::
8
+
9
+ channel = FundingRateChannel(
10
+ symbol='BTC/USDT',
11
+ dataname='data/btc_funding_20210101.csv'
12
+ )
13
+ for event in channel.load():
14
+ print(event.rate, event.mark_price)
15
+ """
16
+
17
+ import csv
18
+ import gzip
19
+ import json
20
+ import math
21
+ from typing import Iterator, Optional
22
+
23
+ from ..channel import DataChannel, DataValidationResult
24
+ from ..events import FundingEvent
25
+ from ..utils.log_message import get_logger
26
+
27
+ logger = get_logger(__name__)
28
+
29
+
30
+ class FundingRateChannel(DataChannel):
31
+ """Funding rate data channel for perpetual contracts.
32
+
33
+ Loads funding rate data from CSV or JSONL files. Validates funding
34
+ rate ranges and mark price consistency.
35
+
36
+ CSV format expects columns: timestamp, rate, mark_price
37
+ Optional columns: next_funding_time, predicted_rate, symbol, exchange
38
+
39
+ Args:
40
+ symbol: Trading pair symbol (e.g., 'BTC/USDT').
41
+ dataname: Path to the data file (CSV or JSONL).
42
+ maxlen: Maximum buffer size.
43
+ validate: Whether to validate incoming events.
44
+ auto_fix: Whether to auto-fix invalid data.
45
+ rate_threshold: Max absolute funding rate for anomaly warning.
46
+ **kwargs: Additional parameters passed to DataChannel.
47
+ """
48
+
49
+ channel_type = "funding"
50
+
51
+ def __init__(
52
+ self,
53
+ symbol,
54
+ dataname=None,
55
+ maxlen=10000,
56
+ validate=True,
57
+ auto_fix=True,
58
+ rate_threshold=0.01,
59
+ **kwargs,
60
+ ):
61
+ """Initialize the funding rate channel.
62
+
63
+ Args:
64
+ symbol: Trading pair symbol (e.g., 'BTC/USDT:USDT').
65
+ dataname: Optional data name for the feed.
66
+ maxlen: Maximum number of events to buffer.
67
+ validate: Whether to validate incoming events.
68
+ auto_fix: Whether to attempt auto-fixing invalid data.
69
+ rate_threshold: Maximum allowed rate difference threshold.
70
+ **kwargs: Additional arguments passed to parent.
71
+ """
72
+ super().__init__(
73
+ symbol=symbol,
74
+ maxlen=maxlen,
75
+ validate=validate,
76
+ auto_fix=auto_fix,
77
+ dataname=dataname,
78
+ **kwargs,
79
+ )
80
+ self._dataname = dataname
81
+ self._rate_threshold = rate_threshold
82
+ self._last_rate = None
83
+
84
+ def _validate_event(self, event) -> DataValidationResult:
85
+ """Validate funding rate specific fields beyond base validation.
86
+
87
+ Additional checks:
88
+ - Rate change anomaly detection
89
+ """
90
+ result = super()._validate_event(event)
91
+ if not result.valid:
92
+ return result
93
+
94
+ # Rate anomaly detection
95
+ if self._last_rate is not None and abs(event.rate) > self._rate_threshold:
96
+ result.warnings.append(
97
+ f"High funding rate: {event.rate} (threshold: {self._rate_threshold})"
98
+ )
99
+
100
+ self._last_rate = event.rate
101
+ return result
102
+
103
+ def load(self) -> Iterator[FundingEvent]:
104
+ """Load funding rate events from file.
105
+
106
+ Supports CSV and JSONL formats.
107
+
108
+ Yields:
109
+ FundingEvent instances.
110
+ """
111
+ if self._dataname is None:
112
+ raise ValueError("dataname (file path) is required for loading")
113
+
114
+ if self._dataname.endswith(".jsonl") or self._dataname.endswith(".jsonl.gz"):
115
+ yield from self._load_jsonl()
116
+ else:
117
+ yield from self._load_csv()
118
+
119
+ def _load_csv(self) -> Iterator[FundingEvent]:
120
+ """Load funding rate events from CSV format.
121
+
122
+ Supports both plain CSV and gzip-compressed CSV (.csv.gz).
123
+ Expects columns: timestamp, rate, mark_price. Optional columns:
124
+ next_funding_time, predicted_rate, symbol, exchange.
125
+
126
+ Yields:
127
+ FundingEvent instances.
128
+ """
129
+ if self._dataname is None:
130
+ raise ValueError("FundingChannel requires a 'dataname' (CSV path) to load from")
131
+ open_func = gzip.open if self._dataname.endswith(".gz") else open
132
+ open_kwargs = (
133
+ {"mode": "rt", "encoding": "utf-8"}
134
+ if self._dataname.endswith(".gz")
135
+ else {"mode": "r", "encoding": "utf-8", "newline": ""}
136
+ )
137
+
138
+ # open_func is gzip.open or builtin open; the conditionally-built
139
+ # open_kwargs dict can't be matched to a specific overload by mypy.
140
+ with open_func(self._dataname, **open_kwargs) as f: # type: ignore[call-overload]
141
+ reader = csv.DictReader(f)
142
+
143
+ required = {"timestamp", "rate", "mark_price"}
144
+ if reader.fieldnames:
145
+ missing = required - set(reader.fieldnames)
146
+ if missing:
147
+ raise ValueError(
148
+ f"Missing required columns: {missing}. Found: {reader.fieldnames}"
149
+ )
150
+
151
+ for row in reader:
152
+ try:
153
+ fe = FundingEvent(
154
+ timestamp=_parse_required_float(row["timestamp"]),
155
+ symbol=row.get("symbol", self.symbol),
156
+ exchange=row.get("exchange", ""),
157
+ asset_type=row.get("asset_type", "swap"),
158
+ rate=_parse_required_float(row["rate"]),
159
+ mark_price=_parse_required_float(row["mark_price"]),
160
+ next_funding_time=_parse_optional_float(row.get("next_funding_time"))
161
+ or 0.0,
162
+ predicted_rate=_parse_optional_float(row.get("predicted_rate")) or 0.0,
163
+ )
164
+ yield fe
165
+ except (ValueError, KeyError) as e:
166
+ logger.warning("Skipping invalid funding row: %s (error: %s)", row, e)
167
+ continue
168
+
169
+ def _load_jsonl(self) -> Iterator[FundingEvent]:
170
+ """Load funding rate events from JSONL format.
171
+
172
+ Supports both plain JSONL and gzip-compressed JSONL (.jsonl.gz).
173
+ Each line should contain a JSON object with timestamp, rate,
174
+ mark_price, and optional fields.
175
+
176
+ Yields:
177
+ FundingEvent instances.
178
+ """
179
+ if self._dataname is None:
180
+ raise ValueError("FundingChannel requires a 'dataname' (JSONL path) to load from")
181
+ open_func = gzip.open if self._dataname.endswith(".gz") else open
182
+ open_kwargs = {"mode": "rt", "encoding": "utf-8"}
183
+
184
+ # open_func is gzip.open or builtin open; the kwargs dict can't be
185
+ # matched to a specific overload by mypy.
186
+ with open_func(self._dataname, **open_kwargs) as f: # type: ignore[call-overload]
187
+ for line_num, line in enumerate(f, 1):
188
+ line = line.strip()
189
+ if not line:
190
+ continue
191
+ try:
192
+ data = json.loads(line)
193
+ fe = FundingEvent(
194
+ timestamp=_parse_required_float(data["timestamp"]),
195
+ symbol=data.get("symbol", self.symbol),
196
+ exchange=data.get("exchange", ""),
197
+ asset_type=data.get("asset_type", "swap"),
198
+ rate=_parse_required_float(data["rate"]),
199
+ mark_price=_parse_required_float(data["mark_price"]),
200
+ next_funding_time=_parse_optional_float(data.get("next_funding_time"))
201
+ or 0.0,
202
+ predicted_rate=_parse_optional_float(data.get("predicted_rate")) or 0.0,
203
+ )
204
+ yield fe
205
+ except (ValueError, KeyError, json.JSONDecodeError) as e:
206
+ logger.warning("Skipping invalid funding JSONL line %d: %s", line_num, e)
207
+ continue
208
+
209
+ def __repr__(self):
210
+ """Return a string representation of the channel.
211
+
212
+ Returns:
213
+ str: Representation showing symbol, dataname, and buffer stats.
214
+ """
215
+ return (
216
+ f"FundingRateChannel(symbol={self.symbol!r}, "
217
+ f"dataname={self._dataname!r}, "
218
+ f"events={self._event_count}, "
219
+ f"buffered={len(self._buffer)})"
220
+ )
221
+
222
+
223
+ def _parse_optional_float(value) -> Optional[float]:
224
+ """Parse an optional float value, returning None for empty/missing.
225
+
226
+ Args:
227
+ value: The value to parse as a float. Can be None, empty string,
228
+ or any value that can be converted to float.
229
+
230
+ Returns:
231
+ The float value if parsing succeeds, None otherwise.
232
+ """
233
+ if value is None or value == "":
234
+ return None
235
+ try:
236
+ number = float(value)
237
+ except (ValueError, TypeError):
238
+ return None
239
+ if not math.isfinite(number):
240
+ return None
241
+ return number
242
+
243
+
244
+ def _parse_required_float(value) -> float:
245
+ number = float(value)
246
+ if not math.isfinite(number):
247
+ raise ValueError(f"Non-finite float value: {value}")
248
+ return number
@@ -0,0 +1,216 @@
1
+ """Thread-safe live event queue for real-time trading.
2
+
3
+ LiveEventQueue provides a thread-safe priority queue for handling events
4
+ from multiple WebSocket connections or data sources in real-time. It uses
5
+ threading locks and supports timeout-based blocking reads.
6
+
7
+ Example::
8
+
9
+ queue = LiveEventQueue(maxsize=100000)
10
+
11
+ # Producer thread (WebSocket callback)
12
+ queue.put(tick_event, priority=EventPriority.TICK)
13
+
14
+ # Consumer thread (strategy processing)
15
+ event = queue.get(timeout=1.0)
16
+ if event:
17
+ process(event)
18
+ """
19
+
20
+ import heapq
21
+ import threading
22
+ import time
23
+ from typing import Optional, cast
24
+
25
+ from ..channel import Event, EventPriority
26
+ from ..utils.log_message import get_logger
27
+
28
+ logger = get_logger(__name__)
29
+
30
+ __all__ = ["LiveEventQueue"]
31
+
32
+
33
+ class LiveEventQueue:
34
+ """Thread-safe priority event queue for live trading.
35
+
36
+ Events are ordered by (timestamp, priority, sequence) just like
37
+ StreamingEventQueue, but with thread-safety for concurrent producers
38
+ and consumers.
39
+
40
+ Args:
41
+ maxsize: Maximum queue capacity. 0 = unlimited.
42
+ drop_policy: What to do when full: 'drop_oldest' or 'drop_newest'.
43
+ """
44
+
45
+ def __init__(self, maxsize=0, drop_policy="drop_oldest"):
46
+ """Initialize the priority queue for live events.
47
+
48
+ Args:
49
+ maxsize: Maximum queue size (0 for unlimited).
50
+ drop_policy: Policy for dropping events when full ('drop_oldest' or 'drop_newest').
51
+ """
52
+ self._heap = []
53
+ self._lock = threading.Lock()
54
+ self._not_empty = threading.Condition(self._lock)
55
+ self._sequence = 0
56
+ self._maxsize = maxsize
57
+ self._drop_policy = drop_policy
58
+ self._total_put = 0
59
+ self._total_get = 0
60
+ self._total_dropped = 0
61
+ self._closed = False
62
+
63
+ def put(
64
+ self,
65
+ event_data,
66
+ priority=EventPriority.TICK,
67
+ channel_type="",
68
+ channel_name="",
69
+ timestamp=None,
70
+ ):
71
+ """Add an event to the queue (thread-safe).
72
+
73
+ Args:
74
+ event_data: The event data (EventData subclass).
75
+ priority: Event priority.
76
+ channel_type: Source channel type.
77
+ channel_name: Source channel/symbol name.
78
+ timestamp: Event timestamp. If None, uses event_data.timestamp
79
+ or current time.
80
+
81
+ Returns:
82
+ True if the event was added, False if dropped.
83
+ """
84
+ if self._closed:
85
+ return False
86
+
87
+ if timestamp is None:
88
+ timestamp = getattr(event_data, "timestamp", time.time())
89
+
90
+ with self._lock:
91
+ event = Event(
92
+ timestamp=timestamp,
93
+ priority=priority,
94
+ sequence=self._sequence,
95
+ channel_type=channel_type,
96
+ channel_name=channel_name,
97
+ data=event_data,
98
+ )
99
+ self._sequence += 1
100
+
101
+ if self._maxsize > 0 and len(self._heap) >= self._maxsize:
102
+ if self._drop_policy == "drop_oldest":
103
+ heapq.heapreplace(self._heap, event)
104
+ self._total_dropped += 1
105
+ else:
106
+ self._total_dropped += 1
107
+ return False
108
+ else:
109
+ heapq.heappush(self._heap, event)
110
+
111
+ self._total_put += 1
112
+ self._not_empty.notify()
113
+ return True
114
+
115
+ def get(self, timeout=None) -> Optional[Event]:
116
+ """Get the next event from the queue (thread-safe, blocking).
117
+
118
+ Args:
119
+ timeout: Maximum seconds to wait. None = block forever.
120
+ 0 = non-blocking.
121
+
122
+ Returns:
123
+ The next Event, or None if timeout expired or queue is closed.
124
+ """
125
+ with self._not_empty:
126
+ if timeout == 0:
127
+ if not self._heap:
128
+ return None
129
+ elif timeout is None:
130
+ while not self._heap and not self._closed:
131
+ self._not_empty.wait()
132
+ else:
133
+ end_time = time.monotonic() + timeout
134
+ while not self._heap and not self._closed:
135
+ remaining = end_time - time.monotonic()
136
+ if remaining <= 0:
137
+ return None
138
+ self._not_empty.wait(timeout=remaining)
139
+
140
+ if not self._heap:
141
+ return None
142
+
143
+ event = heapq.heappop(self._heap)
144
+ self._total_get += 1
145
+ return cast(Event, event)
146
+
147
+ def peek(self) -> Optional[Event]:
148
+ """Peek at the next event without removing it (thread-safe)."""
149
+ with self._lock:
150
+ return self._heap[0] if self._heap else None
151
+
152
+ def close(self):
153
+ """Close the queue, unblocking any waiting consumers."""
154
+ with self._not_empty:
155
+ self._closed = True
156
+ self._not_empty.notify_all()
157
+
158
+ @property
159
+ def closed(self):
160
+ """Whether the queue has been closed."""
161
+ return self._closed
162
+
163
+ @property
164
+ def size(self):
165
+ """Current number of events in the queue."""
166
+ with self._lock:
167
+ return len(self._heap)
168
+
169
+ @property
170
+ def empty(self):
171
+ """Whether the queue is empty."""
172
+ with self._lock:
173
+ return len(self._heap) == 0
174
+
175
+ @property
176
+ def stats(self):
177
+ """Queue statistics."""
178
+ with self._lock:
179
+ return {
180
+ "total_put": self._total_put,
181
+ "total_get": self._total_get,
182
+ "total_dropped": self._total_dropped,
183
+ "current_size": len(self._heap),
184
+ "closed": self._closed,
185
+ }
186
+
187
+ def __len__(self):
188
+ """Return the current number of events in the queue.
189
+
190
+ Returns:
191
+ int: Number of events currently in the queue.
192
+ """
193
+ with self._lock:
194
+ return len(self._heap)
195
+
196
+ def __bool__(self):
197
+ """Return whether the queue has any events.
198
+
199
+ Returns:
200
+ bool: True if the queue has at least one event, False otherwise.
201
+ """
202
+ with self._lock:
203
+ return len(self._heap) > 0
204
+
205
+ def __repr__(self):
206
+ """Return a string representation of the queue.
207
+
208
+ Returns:
209
+ str: Representation showing size and statistics.
210
+ """
211
+ with self._lock:
212
+ return (
213
+ f"LiveEventQueue(size={len(self._heap)}, "
214
+ f"put={self._total_put}, get={self._total_get}, "
215
+ f"dropped={self._total_dropped})"
216
+ )