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,11 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ Live functionality module.
4
+
5
+ Provides real-time data processing and client management functionality.
6
+ """
7
+
8
+ from .client import LiveClient
9
+ from .datahandler import LiveDataHandler
10
+
11
+ __all__ = ["LiveClient", "LiveDataHandler"]
@@ -0,0 +1,352 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ Live client.
4
+
5
+ Manages Bokeh documents and user interactions.
6
+ """
7
+
8
+ from backtrader.utils.log_message import get_logger
9
+
10
+ try:
11
+ from bokeh.layouts import column, layout, row
12
+ from bokeh.models import Button, Select, Spacer, Tabs
13
+
14
+ BOKEH_AVAILABLE = True
15
+ except ImportError:
16
+ BOKEH_AVAILABLE = False
17
+
18
+ from ..utils import get_datanames
19
+ from .datahandler import LiveDataHandler
20
+
21
+ _logger = get_logger(__name__)
22
+
23
+
24
+ class LiveClient:
25
+ """Live client.
26
+
27
+ Provides real-time plotting functionality, including:
28
+ - Data filtering
29
+ - Navigation controls (pause/play/forward/backward)
30
+ - Data updates
31
+
32
+ Attributes:
33
+ doc: Bokeh document instance
34
+ model: Bokeh root model
35
+ lookback: Historical data retention
36
+ fill_gaps: Whether to fill data gaps
37
+ plotgroup: Plot group for filtering
38
+ """
39
+
40
+ NAV_BUTTON_WIDTH = 38
41
+
42
+ def __init__(self, doc, app, strategy, lookback):
43
+ """Initialize live client.
44
+
45
+ Args:
46
+ doc: Bokeh document instance
47
+ app: BacktraderBokeh application instance
48
+ strategy: Strategy instance
49
+ lookback: Historical data retention
50
+ """
51
+ self._app = app
52
+ self._strategy = strategy
53
+ self._refresh_fnc = None
54
+ self._datahandler = None
55
+ self._figurepage = None
56
+ self._paused = False
57
+ self._filter = ""
58
+
59
+ # plotgroup for filter
60
+ self.plotgroup = ""
61
+ # amount of candles to plot
62
+ self.lookback = lookback
63
+ # should gaps in data be filled
64
+ self.fill_gaps = False
65
+ # bokeh document for client
66
+ self.doc = doc
67
+ # model is the root model for bokeh and will be set in baseapp
68
+ self.model = None
69
+
70
+ # append config tab if default tabs should be added
71
+ if hasattr(self._app, "p") and getattr(self._app.p, "use_default_tabs", True):
72
+ from ..tabs import LiveTab
73
+
74
+ if LiveTab not in self._app.tabs:
75
+ self._app.tabs.append(LiveTab)
76
+
77
+ # set plotgroup from app params if provided
78
+ if hasattr(self._app, "p") and hasattr(self._app.p, "filter"):
79
+ if self._app.p.filter and self._app.p.filter.get("group"):
80
+ self.plotgroup = self._app.p.filter["group"]
81
+
82
+ # create figurepage
83
+ self._figid, self._figurepage = self._app.create_figurepage(self._strategy, filldata=False)
84
+
85
+ # create model
86
+ self.model, self._refresh_fnc = self._createmodel()
87
+
88
+ # update model with current figurepage
89
+ self.updatemodel()
90
+
91
+ def _createmodel(self):
92
+ """Create Bokeh model.
93
+
94
+ Returns:
95
+ tuple: (model, refresh_function)
96
+ """
97
+ if not BOKEH_AVAILABLE:
98
+ return None, None
99
+
100
+ client = self
101
+
102
+ def on_select_filter(a, old, new):
103
+ _logger.debug(f"Switching filter to {new}...")
104
+ # ensure datahandler is stopped
105
+ if client._datahandler is not None:
106
+ client._datahandler.stop()
107
+ client._filter = new
108
+ client.updatemodel()
109
+ _logger.debug("Switching filter finished")
110
+
111
+ def on_click_nav_action():
112
+ if not client._paused:
113
+ client._pause()
114
+ else:
115
+ client._resume()
116
+ refresh()
117
+
118
+ def on_click_nav_prev(steps=1):
119
+ client._pause()
120
+ client._set_data_by_idx(client._datahandler.get_last_idx() - steps)
121
+ update_nav_buttons()
122
+
123
+ def on_click_nav_next(steps=1):
124
+ client._pause()
125
+ client._set_data_by_idx(client._datahandler.get_last_idx() + steps)
126
+ update_nav_buttons()
127
+
128
+ def refresh():
129
+ client.doc.add_next_tick_callback(update_nav_buttons)
130
+
131
+ def reset_nav_buttons():
132
+ btn_nav_prev.disabled = True
133
+ btn_nav_next.disabled = True
134
+ btn_nav_action.label = "❙❙"
135
+
136
+ def update_nav_buttons():
137
+ if client._datahandler is None:
138
+ return
139
+
140
+ last_idx = client._datahandler.get_last_idx()
141
+ last_avail_idx = client._app.get_last_idx(client._figid)
142
+
143
+ if last_idx < client.lookback:
144
+ btn_nav_prev.disabled = True
145
+ btn_nav_prev_big.disabled = True
146
+ else:
147
+ btn_nav_prev.disabled = False
148
+ btn_nav_prev_big.disabled = False
149
+
150
+ if last_idx >= last_avail_idx:
151
+ btn_nav_next.disabled = True
152
+ btn_nav_next_big.disabled = True
153
+ else:
154
+ btn_nav_next.disabled = False
155
+ btn_nav_next_big.disabled = False
156
+
157
+ if client._paused:
158
+ btn_nav_action.label = "▶"
159
+ else:
160
+ btn_nav_action.label = "❙❙"
161
+
162
+ # filter selection
163
+ datanames = get_datanames(self._strategy)
164
+ options = [("", "Strategy")]
165
+ for d in datanames:
166
+ options.append(("D" + d, f"Data: {d}"))
167
+ options.append(("G", "Plot Group"))
168
+
169
+ self._filter = "D" + datanames[0] if datanames else ""
170
+
171
+ select_filter = Select(value=self._filter, options=options, width=200)
172
+ select_filter.on_change("value", on_select_filter)
173
+
174
+ # navigation buttons
175
+ btn_nav_prev = Button(label="❮", width=self.NAV_BUTTON_WIDTH)
176
+ btn_nav_prev.on_click(lambda: on_click_nav_prev(1))
177
+
178
+ btn_nav_prev_big = Button(label="❮❮", width=self.NAV_BUTTON_WIDTH)
179
+ btn_nav_prev_big.on_click(lambda: on_click_nav_prev(10))
180
+
181
+ btn_nav_action = Button(label="❙❙", width=self.NAV_BUTTON_WIDTH)
182
+ btn_nav_action.on_click(on_click_nav_action)
183
+
184
+ btn_nav_next = Button(label="❯", width=self.NAV_BUTTON_WIDTH)
185
+ btn_nav_next.on_click(lambda: on_click_nav_next(1))
186
+
187
+ btn_nav_next_big = Button(label="❯❯", width=self.NAV_BUTTON_WIDTH)
188
+ btn_nav_next_big.on_click(lambda: on_click_nav_next(10))
189
+
190
+ # layout
191
+ controls = row(children=[select_filter])
192
+ nav = row(
193
+ children=[
194
+ btn_nav_prev_big,
195
+ btn_nav_prev,
196
+ btn_nav_action,
197
+ btn_nav_next,
198
+ btn_nav_next_big,
199
+ ]
200
+ )
201
+
202
+ # tabs
203
+ tabs = Tabs(
204
+ tabs=[],
205
+ sizing_mode=(
206
+ self._app.scheme.plot_sizing_mode
207
+ if hasattr(self._app, "scheme")
208
+ else "stretch_width"
209
+ ),
210
+ )
211
+ tabs.name = "tabs"
212
+
213
+ # model
214
+ model = layout(
215
+ [
216
+ # app settings, top area
217
+ [column(controls, width_policy="min"), Spacer(), column(nav, width_policy="min")],
218
+ Spacer(height=15),
219
+ # layout for tabs
220
+ [tabs],
221
+ ],
222
+ sizing_mode="stretch_width",
223
+ )
224
+
225
+ return model, refresh
226
+
227
+ def updatemodel(self):
228
+ """Update model."""
229
+ if not BOKEH_AVAILABLE or self.doc is None:
230
+ return
231
+
232
+ self.doc.hold()
233
+
234
+ # update figurepage with filter
235
+ self._app.update_figurepage(filter=self._get_filter())
236
+
237
+ # generate panels
238
+ panels = self._app.generate_model_panels()
239
+
240
+ # add tab panels
241
+ for t in self._app.tabs:
242
+ tab = t(self._app, self._figurepage, self)
243
+ if tab.is_useable():
244
+ panels.append(tab.get_panel())
245
+
246
+ # set all tabs (filter out None)
247
+ tabs = self._get_tabs()
248
+ if tabs is not None:
249
+ tabs.tabs = [p for p in panels if p is not None]
250
+
251
+ # create new data handler
252
+ if self._datahandler is not None:
253
+ self._datahandler.stop()
254
+
255
+ self._datahandler = LiveDataHandler(
256
+ doc=self.doc,
257
+ app=self._app,
258
+ figid=self._figid,
259
+ lookback=self.lookback,
260
+ fill_gaps=self.fill_gaps,
261
+ )
262
+
263
+ # refresh model
264
+ if self._refresh_fnc is not None:
265
+ self._refresh_fnc()
266
+
267
+ self.doc.unhold()
268
+
269
+ def _get_filter(self):
270
+ """Get current filter settings.
271
+
272
+ Returns:
273
+ dict: Filter configuration
274
+ """
275
+ res = {}
276
+ if self._filter.startswith("D"):
277
+ res["dataname"] = self._filter[1:]
278
+ elif self._filter.startswith("G"):
279
+ res["group"] = self.plotgroup
280
+ return res
281
+
282
+ def _pause(self):
283
+ """Pause data updates."""
284
+ self._paused = True
285
+
286
+ def _resume(self):
287
+ """Resume data updates."""
288
+ if not self._paused:
289
+ return
290
+ if self._datahandler is not None:
291
+ self._datahandler.update()
292
+ self._paused = False
293
+
294
+ def _set_data_by_idx(self, idx=None):
295
+ """Set data by index.
296
+
297
+ Args:
298
+ idx: Data index (optional)
299
+ """
300
+ if idx is not None:
301
+ # Ensure index is within valid range
302
+ last_avail_idx = self._app.get_last_idx(self._figid)
303
+ idx = min(idx, last_avail_idx)
304
+ idx = max(idx, self.lookback - 1)
305
+
306
+ # Generate data
307
+ df = self._app.generate_data(
308
+ figid=self._figid,
309
+ end=idx,
310
+ back=self.lookback,
311
+ preserveidx=True,
312
+ fill_gaps=self.fill_gaps,
313
+ )
314
+
315
+ if self._datahandler is not None:
316
+ self._datahandler.set(df)
317
+
318
+ def _get_tabs(self):
319
+ """Get Tabs component.
320
+
321
+ Returns:
322
+ Tabs instance or None
323
+ """
324
+ if self.model is None:
325
+ return None
326
+
327
+ # Find component named 'tabs'
328
+ for child in self.model.children:
329
+ if hasattr(child, "__iter__"):
330
+ for item in child:
331
+ if hasattr(item, "name") and item.name == "tabs":
332
+ return item
333
+ if isinstance(item, Tabs):
334
+ return item
335
+
336
+ return None
337
+
338
+ def next(self):
339
+ """Receive new data and update.
340
+
341
+ Called by LivePlotAnalyzer.next()
342
+ """
343
+ if not self._paused and self._datahandler is not None:
344
+ self._datahandler.update()
345
+
346
+ if self._refresh_fnc is not None:
347
+ self._refresh_fnc()
348
+
349
+ def stop(self):
350
+ """Stop client."""
351
+ if self._datahandler is not None:
352
+ self._datahandler.stop()
@@ -0,0 +1,346 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ Live data handler.
4
+
5
+ Handles real-time data updates and pushes.
6
+ """
7
+
8
+ import importlib.util
9
+ import time
10
+ from enum import Enum
11
+ from threading import Lock, Thread
12
+
13
+ from backtrader.utils.log_message import get_logger
14
+
15
+ TORNADO_AVAILABLE = importlib.util.find_spec("tornado") is not None
16
+
17
+ try:
18
+ import pandas as pd
19
+
20
+ PANDAS_AVAILABLE = True
21
+ except ImportError:
22
+ PANDAS_AVAILABLE = False
23
+
24
+ _logger = get_logger(__name__)
25
+
26
+
27
+ class UpdateType(Enum):
28
+ """Data update type."""
29
+
30
+ ADD = 1 # Add new data
31
+ UPDATE = 2 # Update existing data
32
+
33
+
34
+ class LiveDataHandler:
35
+ """Live data handler.
36
+
37
+ Responsible for receiving, storing and pushing real-time data.
38
+
39
+ Attributes:
40
+ _doc: Bokeh document
41
+ _app: BacktraderBokeh application
42
+ _figid: Figure page ID
43
+ _lookback: Historical data retention
44
+ _fill_gaps: Whether to fill data gaps
45
+ """
46
+
47
+ def __init__(self, doc, app, figid, lookback, fill_gaps=True, timeout=1):
48
+ """Initialize data handler.
49
+
50
+ Args:
51
+ doc: Bokeh document
52
+ app: BacktraderBokeh application
53
+ figid: Figure page ID
54
+ lookback: Historical data retention
55
+ fill_gaps: Whether to fill data gaps
56
+ timeout: Thread timeout
57
+ """
58
+ self._doc = doc
59
+ self._app = app
60
+ self._figid = figid
61
+ self._lookback = lookback
62
+ self._fill_gaps = fill_gaps
63
+ self._timeout = timeout
64
+
65
+ # Get figurepage
66
+ self._figurepage = app.get_figurepage(figid)
67
+
68
+ # Thread related
69
+ self._thread = Thread(target=self._t_thread, daemon=True)
70
+ self._lock = Lock()
71
+ self._running = True
72
+ self._new_data = False
73
+
74
+ # Data storage
75
+ self._datastore = None
76
+ self._last_idx = -1
77
+ self._patches = []
78
+
79
+ # Callbacks
80
+ self._cb_patch = None
81
+ self._cb_add = None
82
+
83
+ # Initial data fill
84
+ self._fill()
85
+
86
+ # Start thread
87
+ self._thread.start()
88
+
89
+ def _fill(self):
90
+ """Fill initial data."""
91
+ if not PANDAS_AVAILABLE:
92
+ return
93
+
94
+ df = self._app.generate_data(
95
+ figid=self._figid, back=self._lookback, preserveidx=True, fill_gaps=self._fill_gaps
96
+ )
97
+
98
+ self._set_data(df)
99
+
100
+ # Initialize CDS columns
101
+ if self._figurepage is not None and hasattr(self._figurepage, "set_cds_columns_from_df"):
102
+ self._figurepage.set_cds_columns_from_df(self._datastore)
103
+
104
+ def _set_data(self, data, idx=None):
105
+ """Set or append data.
106
+
107
+ Args:
108
+ data: DataFrame or Series
109
+ idx: Index (for updating specific row)
110
+ """
111
+ if not PANDAS_AVAILABLE:
112
+ return
113
+
114
+ with self._lock:
115
+ if isinstance(data, pd.DataFrame):
116
+ self._datastore = data
117
+ self._last_idx = -1
118
+ elif isinstance(data, pd.Series):
119
+ if idx is None:
120
+ self._datastore = pd.concat([self._datastore, data.to_frame().T])
121
+ else:
122
+ self._datastore.loc[idx] = data
123
+ else:
124
+ _logger.warning(f"Unsupported data type: {type(data)}")
125
+ return
126
+
127
+ # Keep data length within lookback range
128
+ if self._datastore is not None:
129
+ self._datastore = self._datastore.tail(self._get_data_stream_length())
130
+
131
+ def _cb_push_adds(self):
132
+ """Push new data to ColumnDataSources."""
133
+ if self._datastore is None or "index" not in self._datastore.columns:
134
+ return
135
+
136
+ # Get data not yet pushed
137
+ update_df = self._datastore[self._datastore["index"] > self._last_idx]
138
+
139
+ if update_df.shape[0] == 0:
140
+ return
141
+
142
+ # Update last pushed index
143
+ self._last_idx = update_df["index"].iloc[-1]
144
+
145
+ fp = self._figurepage
146
+ if fp is None:
147
+ return
148
+
149
+ # Push to figurepage
150
+ if hasattr(fp, "get_cds_streamdata_from_df") and hasattr(fp, "cds"):
151
+ data = fp.get_cds_streamdata_from_df(update_df)
152
+ if data:
153
+ _logger.debug(f"Streaming data to figurepage: {len(data)} columns")
154
+ fp.cds.stream(data, self._get_data_stream_length())
155
+
156
+ # Push to each figure
157
+ if hasattr(fp, "figures"):
158
+ for f in fp.figures:
159
+ if hasattr(f, "get_cds_streamdata_from_df") and hasattr(f, "cds"):
160
+ data = f.get_cds_streamdata_from_df(update_df)
161
+ if data:
162
+ f.cds.stream(data, self._get_data_stream_length())
163
+
164
+ def _cb_push_patches(self):
165
+ """Push patch data to ColumnDataSources."""
166
+ patches = []
167
+ while len(self._patches) > 0:
168
+ patches.append(self._patches.pop(0))
169
+
170
+ if len(patches) == 0:
171
+ return
172
+
173
+ fp = self._figurepage
174
+ if fp is None:
175
+ return
176
+
177
+ for patch in patches:
178
+ # Patch figurepage
179
+ if hasattr(fp, "get_cds_patchdata_from_series") and hasattr(fp, "cds"):
180
+ p_data, s_data = fp.get_cds_patchdata_from_series(patch)
181
+ if len(p_data) > 0:
182
+ _logger.debug(f"Patching figurepage: {len(p_data)} fields")
183
+ fp.cds.patch(p_data)
184
+ if len(s_data) > 0:
185
+ fp.cds.stream(s_data, self._get_data_stream_length())
186
+
187
+ # Patch all figures
188
+ if hasattr(fp, "figures"):
189
+ for f in fp.figures:
190
+ if not hasattr(f, "get_cds_patchdata_from_series") or not hasattr(f, "cds"):
191
+ continue
192
+
193
+ # Determine whether to fill NaN
194
+ c_fill_nan = []
195
+ if not self._fill_gaps and hasattr(f, "fill_nan"):
196
+ c_fill_nan = f.fill_nan()
197
+
198
+ p_data, s_data = f.get_cds_patchdata_from_series(patch, c_fill_nan)
199
+ if len(p_data) > 0:
200
+ f.cds.patch(p_data)
201
+ if len(s_data) > 0:
202
+ f.cds.stream(s_data, self._get_data_stream_length())
203
+
204
+ def _push_adds(self):
205
+ """Trigger new data push."""
206
+ if self._doc is None:
207
+ return
208
+
209
+ try:
210
+ if self._cb_add is not None:
211
+ self._doc.remove_next_tick_callback(self._cb_add)
212
+ except ValueError:
213
+ # Callback was already consumed/removed by Bokeh; nothing to undo.
214
+ _logger.debug("datahandler:214 ignored ValueError")
215
+
216
+ self._cb_add = self._doc.add_next_tick_callback(self._cb_push_adds)
217
+
218
+ def _push_patches(self):
219
+ """Trigger patch data push."""
220
+ if self._doc is None:
221
+ return
222
+
223
+ try:
224
+ if self._cb_patch is not None:
225
+ self._doc.remove_next_tick_callback(self._cb_patch)
226
+ except ValueError:
227
+ # Callback was already consumed/removed by Bokeh; nothing to undo.
228
+ _logger.debug("datahandler:228 ignored ValueError")
229
+
230
+ self._cb_patch = self._doc.add_next_tick_callback(self._cb_push_patches)
231
+
232
+ def _process(self, rows):
233
+ """Process new data rows.
234
+
235
+ Args:
236
+ rows: DataFrame containing new data
237
+ """
238
+ if not PANDAS_AVAILABLE or rows is None:
239
+ return
240
+
241
+ for idx, row in rows.iterrows():
242
+ if (
243
+ self._datastore is not None
244
+ and self._datastore.shape[0] > 0
245
+ and "index" in self._datastore.columns
246
+ and idx in self._datastore["index"].values
247
+ ):
248
+ update_type = UpdateType.UPDATE
249
+ else:
250
+ update_type = UpdateType.ADD
251
+
252
+ if update_type == UpdateType.UPDATE:
253
+ ds_idx = self._datastore.loc[self._datastore["index"] == idx].index[0]
254
+ self._set_data(row, ds_idx)
255
+ self._patches.append(row)
256
+ self._push_patches()
257
+ else:
258
+ self._set_data(row)
259
+ self._push_adds()
260
+
261
+ def _t_thread(self):
262
+ """Data processing thread."""
263
+ while self._running:
264
+ if self._new_data:
265
+ last_idx = self.get_last_idx()
266
+ last_avail_idx = self._app.get_last_idx(self._figid)
267
+
268
+ if last_avail_idx - last_idx > (2 * self._lookback):
269
+ # If new data exceeds lookback length, load from end
270
+ data = self._app.generate_data(
271
+ figid=self._figid,
272
+ back=self._lookback,
273
+ preserveidx=True,
274
+ fill_gaps=self._fill_gaps,
275
+ )
276
+ else:
277
+ # Otherwise load from last index
278
+ data = self._app.generate_data(
279
+ figid=self._figid,
280
+ start=last_idx,
281
+ preserveidx=True,
282
+ fill_gaps=self._fill_gaps,
283
+ )
284
+
285
+ self._new_data = False
286
+ self._process(data)
287
+
288
+ time.sleep(self._timeout)
289
+
290
+ def _get_data_stream_length(self):
291
+ """Get data stream length.
292
+
293
+ Returns:
294
+ int: Data stream length
295
+ """
296
+ if self._datastore is None:
297
+ return self._lookback
298
+ return min(self._lookback, self._datastore.shape[0])
299
+
300
+ def get_last_idx(self):
301
+ """Get last data index.
302
+
303
+ Returns:
304
+ int: Last index, returns -1 if no data
305
+ """
306
+ if self._datastore is not None and self._datastore.shape[0] > 0:
307
+ if "index" in self._datastore.columns:
308
+ return self._datastore["index"].iloc[-1]
309
+ return -1
310
+
311
+ def set(self, df):
312
+ """Set new DataFrame and push.
313
+
314
+ Args:
315
+ df: New DataFrame
316
+ """
317
+ self._set_data(df)
318
+ self._push_adds()
319
+
320
+ def update(self):
321
+ """Notify that new data is available."""
322
+ if self._running:
323
+ self._new_data = True
324
+
325
+ def stop(self):
326
+ """Stop data handler."""
327
+ self._running = False
328
+
329
+ # Remove pending callbacks
330
+ try:
331
+ if self._cb_patch is not None:
332
+ self._doc.remove_next_tick_callback(self._cb_patch)
333
+ except (ValueError, AttributeError):
334
+ # Callback already gone or doc detached during shutdown; ignore.
335
+ _logger.debug("datahandler:335 ignored ValueError,AttributeError")
336
+
337
+ try:
338
+ if self._cb_add is not None:
339
+ self._doc.remove_next_tick_callback(self._cb_add)
340
+ except (ValueError, AttributeError):
341
+ # Callback already gone or doc detached during shutdown; ignore.
342
+ _logger.debug("datahandler:342 ignored ValueError,AttributeError")
343
+
344
+ # Wait for thread to finish
345
+ if self._thread.is_alive():
346
+ self._thread.join(timeout=0.5)