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.
- back_trader_python-1.4.0.dist-info/METADATA +1491 -0
- back_trader_python-1.4.0.dist-info/RECORD +465 -0
- back_trader_python-1.4.0.dist-info/WHEEL +5 -0
- back_trader_python-1.4.0.dist-info/licenses/LICENSE +674 -0
- back_trader_python-1.4.0.dist-info/top_level.txt +1 -0
- backtrader/__init__.py +148 -0
- backtrader/_cerebro/__init__.py +5 -0
- backtrader/_cerebro/channel.py +382 -0
- backtrader/_cerebro/execution.py +377 -0
- backtrader/_cerebro/lifecycle.py +143 -0
- backtrader/_cerebro/notifications.py +150 -0
- backtrader/_cerebro/presentation.py +230 -0
- backtrader/_cerebro/registry.py +593 -0
- backtrader/_cerebro/runnext.py +551 -0
- backtrader/_cerebro/runonce.py +142 -0
- backtrader/analyzer.py +594 -0
- backtrader/analyzers/__init__.py +50 -0
- backtrader/analyzers/annualreturn.py +226 -0
- backtrader/analyzers/calmar.py +165 -0
- backtrader/analyzers/drawdown.py +287 -0
- backtrader/analyzers/leverage.py +112 -0
- backtrader/analyzers/logreturnsrolling.py +190 -0
- backtrader/analyzers/periodstats.py +153 -0
- backtrader/analyzers/positions.py +119 -0
- backtrader/analyzers/pyfolio.py +470 -0
- backtrader/analyzers/returns.py +192 -0
- backtrader/analyzers/sharpe.py +307 -0
- backtrader/analyzers/sharpe_ratio_stats.py +534 -0
- backtrader/analyzers/sqn.py +112 -0
- backtrader/analyzers/timereturn.py +192 -0
- backtrader/analyzers/total_value.py +75 -0
- backtrader/analyzers/tradeanalyzer.py +278 -0
- backtrader/analyzers/transactions.py +141 -0
- backtrader/analyzers/vwr.py +245 -0
- backtrader/bokeh/__init__.py +155 -0
- backtrader/bokeh/analyzers/__init__.py +13 -0
- backtrader/bokeh/analyzers/plot.py +192 -0
- backtrader/bokeh/analyzers/recorder.py +181 -0
- backtrader/bokeh/app.py +1094 -0
- backtrader/bokeh/live/__init__.py +11 -0
- backtrader/bokeh/live/client.py +352 -0
- backtrader/bokeh/live/datahandler.py +346 -0
- backtrader/bokeh/plot_adapter.py +200 -0
- backtrader/bokeh/schemes/__init__.py +14 -0
- backtrader/bokeh/schemes/blackly.py +76 -0
- backtrader/bokeh/schemes/scheme.py +150 -0
- backtrader/bokeh/schemes/tradimo.py +82 -0
- backtrader/bokeh/tab.py +125 -0
- backtrader/bokeh/tabs/__init__.py +30 -0
- backtrader/bokeh/tabs/analyzer.py +120 -0
- backtrader/bokeh/tabs/config.py +154 -0
- backtrader/bokeh/tabs/live.py +109 -0
- backtrader/bokeh/tabs/log.py +185 -0
- backtrader/bokeh/tabs/metadata.py +182 -0
- backtrader/bokeh/tabs/performance.py +359 -0
- backtrader/bokeh/tabs/source.py +70 -0
- backtrader/bokeh/utils/__init__.py +8 -0
- backtrader/bokeh/utils/helpers.py +167 -0
- backtrader/bokeh/webapp.py +164 -0
- backtrader/broker.py +478 -0
- backtrader/brokers/__init__.py +36 -0
- backtrader/brokers/bbroker.py +2576 -0
- backtrader/brokers/btapibroker.py +8227 -0
- backtrader/brokers/hft/__init__.py +89 -0
- backtrader/brokers/hft/binance_bbo.py +625 -0
- backtrader/brokers/hft/binance_bbo_compare.py +1398 -0
- backtrader/brokers/hft/examples.py +1228 -0
- backtrader/brokers/hft/exchange.py +380 -0
- backtrader/brokers/hft/latency.py +309 -0
- backtrader/brokers/hft/matching_core.py +572 -0
- backtrader/brokers/hft/queue.py +238 -0
- backtrader/brokers/hft/recorder.py +88 -0
- backtrader/brokers/hft/state.py +138 -0
- backtrader/brokers/impact_models.py +118 -0
- backtrader/brokers/mixbroker.py +895 -0
- backtrader/brokers/tickbroker.py +1991 -0
- backtrader/btrun/__init__.py +12 -0
- backtrader/btrun/btrun.py +1218 -0
- backtrader/cerebro.py +828 -0
- backtrader/channel.py +682 -0
- backtrader/channels/__init__.py +23 -0
- backtrader/channels/bridge.py +186 -0
- backtrader/channels/funding.py +248 -0
- backtrader/channels/live_queue.py +216 -0
- backtrader/channels/live_validator.py +294 -0
- backtrader/channels/orderbook.py +257 -0
- backtrader/channels/tick.py +202 -0
- backtrader/comminfo.py +665 -0
- backtrader/commissions/__init__.py +106 -0
- backtrader/commissions/ctpoption.py +993 -0
- backtrader/configs/account_config_example.yaml +8 -0
- backtrader/dataseries.py +379 -0
- backtrader/errors.py +106 -0
- backtrader/events.py +980 -0
- backtrader/feed.py +1523 -0
- backtrader/feeds/__init__.py +75 -0
- backtrader/feeds/barrier.py +2006 -0
- backtrader/feeds/blaze.py +118 -0
- backtrader/feeds/btapifeed.py +1538 -0
- backtrader/feeds/btcsv.py +203 -0
- backtrader/feeds/chainer.py +114 -0
- backtrader/feeds/cryptohftdata.py +164 -0
- backtrader/feeds/csvgeneric.py +1205 -0
- backtrader/feeds/ctpcohort.py +1051 -0
- backtrader/feeds/influxfeed.py +158 -0
- backtrader/feeds/livefeed.py +71 -0
- backtrader/feeds/mixed_channel.py +108 -0
- backtrader/feeds/mt4csv.py +42 -0
- backtrader/feeds/pandafeed.py +381 -0
- backtrader/feeds/quandl.py +256 -0
- backtrader/feeds/rollover.py +229 -0
- backtrader/feeds/sierrachart.py +30 -0
- backtrader/feeds/vchart.py +162 -0
- backtrader/feeds/vchartcsv.py +84 -0
- backtrader/feeds/vchartfile.py +153 -0
- backtrader/feeds/yahoo.py +399 -0
- backtrader/fillers.py +148 -0
- backtrader/filters/__init__.py +34 -0
- backtrader/filters/bsplitter.py +127 -0
- backtrader/filters/calendardays.py +121 -0
- backtrader/filters/datafiller.py +192 -0
- backtrader/filters/datafilter.py +74 -0
- backtrader/filters/daysteps.py +96 -0
- backtrader/filters/heikinashi.py +63 -0
- backtrader/filters/renko.py +164 -0
- backtrader/filters/session.py +289 -0
- backtrader/flt.py +80 -0
- backtrader/functions.py +960 -0
- backtrader/indicator.py +449 -0
- backtrader/indicators/__init__.py +148 -0
- backtrader/indicators/accdecoscillator.py +110 -0
- backtrader/indicators/aroon.py +300 -0
- backtrader/indicators/atr.py +315 -0
- backtrader/indicators/awesomeoscillator.py +122 -0
- backtrader/indicators/basicops.py +834 -0
- backtrader/indicators/bollinger.py +223 -0
- backtrader/indicators/cci.py +89 -0
- backtrader/indicators/channels_ext.py +83 -0
- backtrader/indicators/contrib/__init__.py +228 -0
- backtrader/indicators/contrib/absolutely_no_lag_lwma.py +28 -0
- backtrader/indicators/contrib/absolutely_no_lag_lwma_color.py +44 -0
- backtrader/indicators/contrib/accumulation_distribution_line.py +92 -0
- backtrader/indicators/contrib/adx_cross_hull_style_indicator.py +249 -0
- backtrader/indicators/contrib/adxdmi.py +34 -0
- backtrader/indicators/contrib/ai_acceleration_deceleration_oscillator.py +34 -0
- backtrader/indicators/contrib/altr_trend_signal_v22.py +85 -0
- backtrader/indicators/contrib/anchored_momentum_line.py +115 -0
- backtrader/indicators/contrib/any_range_cld_tail_indicator.py +82 -0
- backtrader/indicators/contrib/aroon_horn_sign_indicator.py +96 -0
- backtrader/indicators/contrib/aroon_oscillator_sign_alert.py +50 -0
- backtrader/indicators/contrib/arrows_curves_indicator.py +112 -0
- backtrader/indicators/contrib/as_ctrend_indicator.py +143 -0
- backtrader/indicators/contrib/asimmetric_stoch_nr_indicator.py +187 -0
- backtrader/indicators/contrib/atr_normalize_histogram.py +118 -0
- backtrader/indicators/contrib/average_change_candle.py +165 -0
- backtrader/indicators/contrib/bb_squeeze_indicator.py +60 -0
- backtrader/indicators/contrib/bezier_st_dev_indicator.py +135 -0
- backtrader/indicators/contrib/binary_wave_indicator.py +233 -0
- backtrader/indicators/contrib/blau_c_momentum_indicator.py +123 -0
- backtrader/indicators/contrib/blau_cmi_indicator.py +141 -0
- backtrader/indicators/contrib/blau_csi.py +76 -0
- backtrader/indicators/contrib/blau_ergodic.py +53 -0
- backtrader/indicators/contrib/blau_t_stoch_i.py +72 -0
- backtrader/indicators/contrib/blau_ts_stochastic.py +85 -0
- backtrader/indicators/contrib/blau_tvi.py +55 -0
- backtrader/indicators/contrib/brain_trend2_indicator.py +128 -0
- backtrader/indicators/contrib/brain_trend_signal_proxy.py +47 -0
- backtrader/indicators/contrib/brake_parb_indicator.py +85 -0
- backtrader/indicators/contrib/breakout_bars_trend_v2.py +121 -0
- backtrader/indicators/contrib/bsi_indicator.py +87 -0
- backtrader/indicators/contrib/bulls_bears_eyes.py +67 -0
- backtrader/indicators/contrib/bulls_power.py +56 -0
- backtrader/indicators/contrib/bw_wise_man1_signal.py +102 -0
- backtrader/indicators/contrib/bykov_trend_indicator.py +85 -0
- backtrader/indicators/contrib/candle_stop_color.py +46 -0
- backtrader/indicators/contrib/candles_x_smoothed_indicator.py +69 -0
- backtrader/indicators/contrib/candlesticks_bw.py +45 -0
- backtrader/indicators/contrib/caudate_x_period_candle_color.py +56 -0
- backtrader/indicators/contrib/cci_histogram_indicator.py +53 -0
- backtrader/indicators/contrib/cci_woodies_indicator.py +80 -0
- backtrader/indicators/contrib/center_of_gravity_candle_indicator.py +83 -0
- backtrader/indicators/contrib/center_of_gravity_indicator.py +70 -0
- backtrader/indicators/contrib/cg_oscillator.py +40 -0
- backtrader/indicators/contrib/close_line_cci.py +38 -0
- backtrader/indicators/contrib/close_price_fractals.py +47 -0
- backtrader/indicators/contrib/color3rd_gen_xma_indicator.py +122 -0
- backtrader/indicators/contrib/color_bb_candles_indicator.py +108 -0
- backtrader/indicators/contrib/color_coppock_indicator.py +157 -0
- backtrader/indicators/contrib/color_hma.py +71 -0
- backtrader/indicators/contrib/color_j_variation_indicator.py +53 -0
- backtrader/indicators/contrib/color_metro_de_marker_indicator.py +78 -0
- backtrader/indicators/contrib/color_metro_stochastic_indicator.py +93 -0
- backtrader/indicators/contrib/color_metro_wpr_indicator.py +85 -0
- backtrader/indicators/contrib/color_schaff_de_marker_trend_cycle.py +92 -0
- backtrader/indicators/contrib/color_schaff_trend_cycle_indicator.py +203 -0
- backtrader/indicators/contrib/color_step_xccx_indicator.py +193 -0
- backtrader/indicators/contrib/color_x2_ma.py +49 -0
- backtrader/indicators/contrib/color_x_derivative.py +63 -0
- backtrader/indicators/contrib/color_zerolag_de_marker.py +84 -0
- backtrader/indicators/contrib/corrected_average_indicator.py +127 -0
- backtrader/indicators/contrib/darvas_boxes_system.py +73 -0
- backtrader/indicators/contrib/dema_range_channel_color.py +42 -0
- backtrader/indicators/contrib/derivative_indicator.py +95 -0
- backtrader/indicators/contrib/digital_ft01_indicator.py +112 -0
- backtrader/indicators/contrib/digital_macd.py +200 -0
- backtrader/indicators/contrib/donchian_channels_system.py +45 -0
- backtrader/indicators/contrib/dots_indicator.py +93 -0
- backtrader/indicators/contrib/ef_distance_indicator.py +82 -0
- backtrader/indicators/contrib/ema_rsi_va.py +80 -0
- backtrader/indicators/contrib/envelopes_jp_alonso.py +32 -0
- backtrader/indicators/contrib/f2a_ao_indicator.py +120 -0
- backtrader/indicators/contrib/fatl_filter.py +179 -0
- backtrader/indicators/contrib/fibo_candles_indicator.py +78 -0
- backtrader/indicators/contrib/fine_tuning_ma.py +100 -0
- backtrader/indicators/contrib/fisher_org_v1.py +102 -0
- backtrader/indicators/contrib/fisher_org_v1_sign.py +118 -0
- backtrader/indicators/contrib/force_index_ema.py +96 -0
- backtrader/indicators/contrib/force_index_ema_2.py +27 -0
- backtrader/indicators/contrib/forecast_oscilator.py +145 -0
- backtrader/indicators/contrib/fractal_amambk.py +81 -0
- backtrader/indicators/contrib/frama_series.py +84 -0
- backtrader/indicators/contrib/frasm_av2_indicator.py +104 -0
- backtrader/indicators/contrib/go_indicator.py +93 -0
- backtrader/indicators/contrib/hlr_indicator.py +95 -0
- backtrader/indicators/contrib/hma.py +50 -0
- backtrader/indicators/contrib/i4_drfv2.py +34 -0
- backtrader/indicators/contrib/i4_drfv3.py +38 -0
- backtrader/indicators/contrib/i_anch_mom_indicator.py +72 -0
- backtrader/indicators/contrib/i_de_marker_sign_indicator.py +64 -0
- backtrader/indicators/contrib/i_gap_indicator.py +45 -0
- backtrader/indicators/contrib/i_stoch_komposter_indicator.py +77 -0
- backtrader/indicators/contrib/i_trend_indicator.py +125 -0
- backtrader/indicators/contrib/iamma_indicator.py +39 -0
- backtrader/indicators/contrib/indexed_moving_average.py +33 -0
- backtrader/indicators/contrib/instantaneous_trend_filter_indicator.py +51 -0
- backtrader/indicators/contrib/inverse_reaction_indicator.py +41 -0
- backtrader/indicators/contrib/irsi_sign_indicator.py +95 -0
- backtrader/indicators/contrib/iwpr_sign_indicator.py +59 -0
- backtrader/indicators/contrib/j_brain_trend1_sig_indicator.py +233 -0
- backtrader/indicators/contrib/j_tpo_proxy.py +32 -0
- backtrader/indicators/contrib/jma_slope_indicator.py +73 -0
- backtrader/indicators/contrib/kalman_filter_indicator.py +119 -0
- backtrader/indicators/contrib/kalman_filter_line.py +127 -0
- backtrader/indicators/contrib/kama_indicator.py +150 -0
- backtrader/indicators/contrib/karacatica_indicator.py +99 -0
- backtrader/indicators/contrib/kdj_indicator.py +59 -0
- backtrader/indicators/contrib/kwan_ccc_indicator.py +195 -0
- backtrader/indicators/contrib/kwan_nrp_indicator.py +113 -0
- backtrader/indicators/contrib/kwan_rdp_indicator.py +192 -0
- backtrader/indicators/contrib/laguerre_adx_indicator.py +85 -0
- backtrader/indicators/contrib/laguerre_filter_indicator.py +66 -0
- backtrader/indicators/contrib/laguerre_plus_di_proxy.py +57 -0
- backtrader/indicators/contrib/laguerre_roc_indicator.py +81 -0
- backtrader/indicators/contrib/le_man_signal_indicator.py +63 -0
- backtrader/indicators/contrib/linear_reg_slope_v2_indicator.py +136 -0
- backtrader/indicators/contrib/loco_indicator.py +88 -0
- backtrader/indicators/contrib/lrma_indicator.py +185 -0
- backtrader/indicators/contrib/lsma_angle_indicator.py +106 -0
- backtrader/indicators/contrib/ma_rounding_channel_indicator.py +149 -0
- backtrader/indicators/contrib/macd2_indicator.py +61 -0
- backtrader/indicators/contrib/macd_candle_indicator.py +80 -0
- backtrader/indicators/contrib/malr_indicator.py +77 -0
- backtrader/indicators/contrib/momentum_candle_sign_indicator.py +51 -0
- backtrader/indicators/contrib/moving_average_fn_indicator.py +139 -0
- backtrader/indicators/contrib/mt5_stochastic_close_close.py +57 -0
- backtrader/indicators/contrib/muv_nor_diff_cloud_indicator.py +107 -0
- backtrader/indicators/contrib/non_lag_dot_indicator.py +124 -0
- backtrader/indicators/contrib/nrtr_extr_indicator.py +95 -0
- backtrader/indicators/contrib/nrtr_indicator.py +95 -0
- backtrader/indicators/contrib/p_channel_system.py +40 -0
- backtrader/indicators/contrib/percent_envelope.py +37 -0
- backtrader/indicators/contrib/percentage_crossover_channel.py +47 -0
- backtrader/indicators/contrib/pivot_zig_zag_proxy.py +47 -0
- backtrader/indicators/contrib/price_channel_stop_indicator.py +104 -0
- backtrader/indicators/contrib/price_extreme_channel.py +35 -0
- backtrader/indicators/contrib/qqe_cloud_indicator.py +129 -0
- backtrader/indicators/contrib/ravi_indicator.py +40 -0
- backtrader/indicators/contrib/raw_close_close_stochastic.py +74 -0
- backtrader/indicators/contrib/rd_trend_trigger_indicator.py +51 -0
- backtrader/indicators/contrib/renko_level.py +85 -0
- backtrader/indicators/contrib/renko_line_break.py +91 -0
- backtrader/indicators/contrib/rftl_indicator.py +41 -0
- backtrader/indicators/contrib/rkd_indicator.py +53 -0
- backtrader/indicators/contrib/roc2_vg_indicator.py +68 -0
- backtrader/indicators/contrib/rsi_histogram_indicator.py +43 -0
- backtrader/indicators/contrib/rsi_slowdown.py +57 -0
- backtrader/indicators/contrib/rsioma_v2.py +41 -0
- backtrader/indicators/contrib/rvi_histogram_indicator.py +107 -0
- backtrader/indicators/contrib/safe_adx.py +89 -0
- backtrader/indicators/contrib/shared_strategy_indicators.py +1651 -0
- backtrader/indicators/contrib/sidus_indicator.py +105 -0
- backtrader/indicators/contrib/silver_trend_indicator.py +79 -0
- backtrader/indicators/contrib/sliding_range_color.py +56 -0
- backtrader/indicators/contrib/slow_stoch.py +42 -0
- backtrader/indicators/contrib/smoothed_adx_indicator.py +86 -0
- backtrader/indicators/contrib/smoothed_rsi.py +31 -0
- backtrader/indicators/contrib/spearman_rank_correlation_histogram.py +60 -0
- backtrader/indicators/contrib/stalin_indicator.py +152 -0
- backtrader/indicators/contrib/starter_laguerre_filter.py +62 -0
- backtrader/indicators/contrib/step_manrtr_indicator.py +137 -0
- backtrader/indicators/contrib/stochastic_histogram_indicator.py +143 -0
- backtrader/indicators/contrib/t3_alarm_indicator.py +125 -0
- backtrader/indicators/contrib/t3_average.py +76 -0
- backtrader/indicators/contrib/t3_indicator.py +40 -0
- backtrader/indicators/contrib/the20s_v020_signal.py +93 -0
- backtrader/indicators/contrib/three_candles_indicator.py +70 -0
- backtrader/indicators/contrib/three_line_break_indicator.py +64 -0
- backtrader/indicators/contrib/time_line.py +57 -0
- backtrader/indicators/contrib/trading_channel_index_proxy.py +48 -0
- backtrader/indicators/contrib/trend_arrows_indicator.py +109 -0
- backtrader/indicators/contrib/trend_continuation_indicator.py +127 -0
- backtrader/indicators/contrib/trend_intensity_index_proxy.py +51 -0
- backtrader/indicators/contrib/trend_manager_indicator.py +39 -0
- backtrader/indicators/contrib/tri_x_candle_indicator.py +51 -0
- backtrader/indicators/contrib/trigger_line.py +66 -0
- backtrader/indicators/contrib/triple_ema_rate.py +34 -0
- backtrader/indicators/contrib/trvi_indicator.py +194 -0
- backtrader/indicators/contrib/two_pb_ideal_xosma_indicator.py +127 -0
- backtrader/indicators/contrib/ultra_absolutely_no_lag_lwma_color.py +92 -0
- backtrader/indicators/contrib/ultra_wpr_indicator.py +173 -0
- backtrader/indicators/contrib/up_down_candle_strength.py +68 -0
- backtrader/indicators/contrib/vinin_i_trend_indicator.py +139 -0
- backtrader/indicators/contrib/volume_weighted_ma_indicator.py +78 -0
- backtrader/indicators/contrib/volume_weighted_ma_st_dev_indicator.py +111 -0
- backtrader/indicators/contrib/vwap_close_indicator.py +65 -0
- backtrader/indicators/contrib/vwma_candle.py +57 -0
- backtrader/indicators/contrib/vwma_digit_system.py +70 -0
- backtrader/indicators/contrib/wami.py +43 -0
- backtrader/indicators/contrib/wprsi_signal_indicator.py +105 -0
- backtrader/indicators/contrib/x_de_marker_histogram_vol_direct_indicator.py +145 -0
- backtrader/indicators/contrib/x_fisher_indicator.py +64 -0
- backtrader/indicators/contrib/xcci_histogram_vol_direct_indicator.py +56 -0
- backtrader/indicators/contrib/xcci_histogram_vol_indicator.py +85 -0
- backtrader/indicators/contrib/xma_ichimoku.py +163 -0
- backtrader/indicators/contrib/xma_ishimoku_channel_indicator.py +65 -0
- backtrader/indicators/contrib/xma_ishimoku_line.py +68 -0
- backtrader/indicators/contrib/xma_range_bands_indicator.py +107 -0
- backtrader/indicators/contrib/xmacd_indicator.py +70 -0
- backtrader/indicators/contrib/xrsi_de_marker_histogram.py +67 -0
- backtrader/indicators/contrib/xrsi_histogram_vol_direct_indicator.py +52 -0
- backtrader/indicators/contrib/xrsi_histogram_vol_indicator.py +81 -0
- backtrader/indicators/contrib/xrvi_indicator.py +130 -0
- backtrader/indicators/contrib/zero_lag_macd.py +36 -0
- backtrader/indicators/contrib/zig_zag_recent_pivot_signal.py +90 -0
- backtrader/indicators/contrib/zpf_indicator.py +115 -0
- backtrader/indicators/crossover.py +337 -0
- backtrader/indicators/dema.py +175 -0
- backtrader/indicators/demarker.py +270 -0
- backtrader/indicators/deviation.py +284 -0
- backtrader/indicators/directionalmove.py +1071 -0
- backtrader/indicators/dma.py +112 -0
- backtrader/indicators/dpo.py +96 -0
- backtrader/indicators/dv2.py +56 -0
- backtrader/indicators/ema.py +145 -0
- backtrader/indicators/envelope.py +475 -0
- backtrader/indicators/hadelta.py +198 -0
- backtrader/indicators/heikinashi.py +153 -0
- backtrader/indicators/hma.py +153 -0
- backtrader/indicators/hurst.py +151 -0
- backtrader/indicators/ichimoku.py +267 -0
- backtrader/indicators/kama.py +181 -0
- backtrader/indicators/kst.py +159 -0
- backtrader/indicators/lrsi.py +125 -0
- backtrader/indicators/mabase.py +147 -0
- backtrader/indicators/macd.py +322 -0
- backtrader/indicators/momentum.py +267 -0
- backtrader/indicators/moneyflow.py +237 -0
- backtrader/indicators/mt5atr.py +124 -0
- backtrader/indicators/myind.py +179 -0
- backtrader/indicators/obv.py +94 -0
- backtrader/indicators/ols.py +265 -0
- backtrader/indicators/oscillator.py +161 -0
- backtrader/indicators/percentchange.py +83 -0
- backtrader/indicators/percentrank.py +46 -0
- backtrader/indicators/pivotpoint.py +469 -0
- backtrader/indicators/prettygoodoscillator.py +113 -0
- backtrader/indicators/priceops_ext.py +123 -0
- backtrader/indicators/priceoscillator.py +262 -0
- backtrader/indicators/psar.py +212 -0
- backtrader/indicators/rmi.py +69 -0
- backtrader/indicators/rsi.py +440 -0
- backtrader/indicators/sma.py +141 -0
- backtrader/indicators/smma.py +116 -0
- backtrader/indicators/spread.py +54 -0
- backtrader/indicators/stochastic.py +263 -0
- backtrader/indicators/supertrend.py +436 -0
- backtrader/indicators/trend_ext.py +105 -0
- backtrader/indicators/trix.py +202 -0
- backtrader/indicators/tsi.py +155 -0
- backtrader/indicators/ultimateoscillator.py +158 -0
- backtrader/indicators/vortex.py +62 -0
- backtrader/indicators/williams.py +194 -0
- backtrader/indicators/wma.py +103 -0
- backtrader/indicators/zlema.py +135 -0
- backtrader/indicators/zlind.py +104 -0
- backtrader/linebuffer.py +3155 -0
- backtrader/lineiterator.py +2911 -0
- backtrader/lineroot.py +1106 -0
- backtrader/lineseries.py +2559 -0
- backtrader/live_trading/__init__.py +31 -0
- backtrader/live_trading/interface.py +404 -0
- backtrader/mathsupport.py +94 -0
- backtrader/metabase.py +1804 -0
- backtrader/mixins/__init__.py +21 -0
- backtrader/mixins/singleton.py +118 -0
- backtrader/observer.py +106 -0
- backtrader/observers/__init__.py +45 -0
- backtrader/observers/benchmark.py +126 -0
- backtrader/observers/broker.py +184 -0
- backtrader/observers/buysell.py +144 -0
- backtrader/observers/drawdown.py +161 -0
- backtrader/observers/logreturns.py +113 -0
- backtrader/observers/timereturn.py +86 -0
- backtrader/observers/trade_logger.py +2972 -0
- backtrader/observers/tradelogger.py +6 -0
- backtrader/observers/trades.py +258 -0
- backtrader/order.py +1114 -0
- backtrader/parameters.py +2345 -0
- backtrader/plot/__init__.py +54 -0
- backtrader/plot/finance.py +1022 -0
- backtrader/plot/formatters.py +200 -0
- backtrader/plot/locator.py +353 -0
- backtrader/plot/multicursor.py +495 -0
- backtrader/plot/plot.py +2500 -0
- backtrader/plot/plot_plotly.py +1351 -0
- backtrader/plot/scheme.py +253 -0
- backtrader/plot/utils.py +104 -0
- backtrader/position.py +290 -0
- backtrader/position_modes.py +132 -0
- backtrader/profiles.py +254 -0
- backtrader/reports/__init__.py +39 -0
- backtrader/reports/charts.py +371 -0
- backtrader/reports/performance.py +620 -0
- backtrader/reports/reporter.py +660 -0
- backtrader/resamplerfilter.py +1001 -0
- backtrader/signal.py +118 -0
- backtrader/signals/__init__.py +17 -0
- backtrader/sizer.py +114 -0
- backtrader/sizers/__init__.py +26 -0
- backtrader/sizers/fixedsize.py +161 -0
- backtrader/sizers/percents_sizer.py +119 -0
- backtrader/store.py +221 -0
- backtrader/stores/__init__.py +33 -0
- backtrader/stores/btapistore.py +15506 -0
- backtrader/stores/livestore.py +137 -0
- backtrader/stores/vchartfile.py +96 -0
- backtrader/strategy.py +3655 -0
- backtrader/talib.py +280 -0
- backtrader/test_helpers.py +96 -0
- backtrader/timer.py +358 -0
- backtrader/trade.py +442 -0
- backtrader/tradingcal.py +361 -0
- backtrader/utils/__init__.py +68 -0
- backtrader/utils/autodict.py +251 -0
- backtrader/utils/date.py +71 -0
- backtrader/utils/dateintern.py +509 -0
- backtrader/utils/flushfile.py +94 -0
- backtrader/utils/fractal.py +101 -0
- backtrader/utils/get_metrics.py +101 -0
- backtrader/utils/load_data.py +209 -0
- backtrader/utils/log_message.py +998 -0
- backtrader/utils/ordereddefaultdict.py +75 -0
- backtrader/utils/py3.py +296 -0
- backtrader/version.py +21 -0
- backtrader/writer.py +372 -0
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Pandas Data Feed Module - Pandas DataFrame integration.
|
|
3
|
+
|
|
4
|
+
This module provides data feeds for loading market data from
|
|
5
|
+
Pandas DataFrames.
|
|
6
|
+
|
|
7
|
+
Classes:
|
|
8
|
+
PandasDirectData: Uses DataFrame tuples as data source.
|
|
9
|
+
PandasData: Uses DataFrame columns as data source.
|
|
10
|
+
|
|
11
|
+
Example:
|
|
12
|
+
>>> import pandas as pd
|
|
13
|
+
>>> df = pd.read_csv('data.csv')
|
|
14
|
+
>>> data = bt.feeds.PandasData(dataname=df)
|
|
15
|
+
>>> cerebro.adddata(data)
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from ..feed import DataBase
|
|
19
|
+
from ..utils import date2num
|
|
20
|
+
from ..utils.log_message import get_logger
|
|
21
|
+
from ..utils.py3 import filter, integer_types, string_types
|
|
22
|
+
|
|
23
|
+
logger = get_logger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class PandasDirectData(DataBase):
|
|
27
|
+
"""
|
|
28
|
+
Uses a Pandas DataFrame as the feed source, iterating directly over the
|
|
29
|
+
tuples returned by "itertuples".
|
|
30
|
+
|
|
31
|
+
This means that all parameters related to lines must have numeric
|
|
32
|
+
values as indices into the tuples
|
|
33
|
+
|
|
34
|
+
Note:
|
|
35
|
+
|
|
36
|
+
- The ``dataname`` parameter is a Pandas DataFrame
|
|
37
|
+
|
|
38
|
+
- A negative value in any of the parameters for the Data lines
|
|
39
|
+
indicates it's not present in the DataFrame
|
|
40
|
+
it is
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
# Parameters
|
|
44
|
+
params = (
|
|
45
|
+
("datetime", 0),
|
|
46
|
+
("open", 1),
|
|
47
|
+
("high", 2),
|
|
48
|
+
("low", 3),
|
|
49
|
+
("close", 4),
|
|
50
|
+
("volume", 5),
|
|
51
|
+
("openinterest", 6),
|
|
52
|
+
)
|
|
53
|
+
# Column names
|
|
54
|
+
datafields = ["datetime", "open", "high", "low", "close", "volume", "openinterest"]
|
|
55
|
+
|
|
56
|
+
def __init__(self):
|
|
57
|
+
"""Initialize the PandasDirect data feed.
|
|
58
|
+
|
|
59
|
+
Prepares for iterating over DataFrame rows.
|
|
60
|
+
"""
|
|
61
|
+
super().__init__() # CRITICAL FIX: Must call parent __init__
|
|
62
|
+
self._rows = None
|
|
63
|
+
|
|
64
|
+
def start(self):
|
|
65
|
+
"""Start the PandasDirect data feed.
|
|
66
|
+
|
|
67
|
+
Creates iterator from DataFrame.
|
|
68
|
+
"""
|
|
69
|
+
super().start()
|
|
70
|
+
|
|
71
|
+
# reset the iterator on each start
|
|
72
|
+
self._rows = self.p.dataname.itertuples()
|
|
73
|
+
|
|
74
|
+
def _load(self):
|
|
75
|
+
# Try to get next row, return False if error
|
|
76
|
+
try:
|
|
77
|
+
row = next(self._rows)
|
|
78
|
+
except StopIteration:
|
|
79
|
+
return False
|
|
80
|
+
|
|
81
|
+
# Set the standard datafields - except for datetime
|
|
82
|
+
# For columns other than datetime, add data to lines based on column names
|
|
83
|
+
for datafield in self.getlinealiases():
|
|
84
|
+
if datafield == "datetime":
|
|
85
|
+
continue
|
|
86
|
+
|
|
87
|
+
# get the column index
|
|
88
|
+
colidx = getattr(self.params, datafield)
|
|
89
|
+
|
|
90
|
+
if colidx < 0:
|
|
91
|
+
# column is not present -- skip
|
|
92
|
+
continue
|
|
93
|
+
|
|
94
|
+
# get the line to be set
|
|
95
|
+
line = getattr(self.lines, datafield)
|
|
96
|
+
# indexing for pandas: 1st is colum, then row
|
|
97
|
+
line[0] = row[colidx]
|
|
98
|
+
|
|
99
|
+
# datetime
|
|
100
|
+
# For datetime, get the index of datetime column, then get time
|
|
101
|
+
colidx = getattr(self.params, "datetime")
|
|
102
|
+
tstamp = row[colidx]
|
|
103
|
+
|
|
104
|
+
# convert to float via datetime and store it
|
|
105
|
+
# Convert timestamp to specific datetime format, then convert to number
|
|
106
|
+
dt = tstamp.to_pydatetime()
|
|
107
|
+
dtnum = date2num(dt)
|
|
108
|
+
|
|
109
|
+
# get the line to be set
|
|
110
|
+
# Get datetime line, then save this number
|
|
111
|
+
line = getattr(self.lines, "datetime")
|
|
112
|
+
line[0] = dtnum
|
|
113
|
+
|
|
114
|
+
# Done ... return
|
|
115
|
+
return True
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class PandasData(DataBase):
|
|
119
|
+
"""
|
|
120
|
+
Uses a Pandas DataFrame as the feed source, using indices into column
|
|
121
|
+
names (which can be "numeric")
|
|
122
|
+
|
|
123
|
+
This means that all parameters related to lines must have numeric
|
|
124
|
+
values as indices into the tuples
|
|
125
|
+
|
|
126
|
+
Params:
|
|
127
|
+
|
|
128
|
+
- ``nocase`` (default *True*) case-insensitive match of column names
|
|
129
|
+
|
|
130
|
+
Note:
|
|
131
|
+
|
|
132
|
+
- The ``dataname`` parameter is a Pandas DataFrame
|
|
133
|
+
|
|
134
|
+
- Values possible for datetime
|
|
135
|
+
|
|
136
|
+
- None: the index contains the datetime
|
|
137
|
+
- -1: no index, autodetect column
|
|
138
|
+
- >= 0 or string: specific colum identifier
|
|
139
|
+
|
|
140
|
+
- For other lines parameters
|
|
141
|
+
|
|
142
|
+
- None: column not present
|
|
143
|
+
- -1: autodetect
|
|
144
|
+
- >= 0 or string: specific colum identifier
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
# Parameters and their meanings
|
|
148
|
+
params = (
|
|
149
|
+
("nocase", True),
|
|
150
|
+
# Possible values for datetime (must always be present)
|
|
151
|
+
# None: datetime is the "index" in the Pandas Dataframe
|
|
152
|
+
# -1: autodetect position or case-wise equal name
|
|
153
|
+
# >= 0: numeric index to the colum in the pandas dataframe
|
|
154
|
+
# string: column name (as index) in the pandas dataframe
|
|
155
|
+
("datetime", None),
|
|
156
|
+
# The possible values below:
|
|
157
|
+
# None : column not present
|
|
158
|
+
# -1: autodetect position or case-wise equal name
|
|
159
|
+
# >= 0: numeric index to the colum in the pandas dataframe
|
|
160
|
+
# string: column name (as index) in the pandas dataframe
|
|
161
|
+
("open", -1),
|
|
162
|
+
("high", -1),
|
|
163
|
+
("low", -1),
|
|
164
|
+
("close", -1),
|
|
165
|
+
("volume", -1),
|
|
166
|
+
("openinterest", -1),
|
|
167
|
+
)
|
|
168
|
+
# Column names of data
|
|
169
|
+
datafields = ["datetime", "open", "high", "low", "close", "volume", "openinterest"]
|
|
170
|
+
|
|
171
|
+
def __init__(self):
|
|
172
|
+
"""Initialize the Pandas data feed.
|
|
173
|
+
|
|
174
|
+
Creates column mappings for DataFrame data access.
|
|
175
|
+
"""
|
|
176
|
+
super().__init__()
|
|
177
|
+
|
|
178
|
+
# these "colnames" can be strings or numeric types
|
|
179
|
+
# Column names, list format
|
|
180
|
+
self._idx = None
|
|
181
|
+
self._df_len = 0
|
|
182
|
+
self._loaditems = None
|
|
183
|
+
self._df_values = None
|
|
184
|
+
self._dt_dtnum = None
|
|
185
|
+
self._coldtime = None
|
|
186
|
+
colnames = list(self.p.dataname.columns.values)
|
|
187
|
+
# If datetime is in index
|
|
188
|
+
if self.p.datetime is None:
|
|
189
|
+
# datetime is expected as index col and hence not returned
|
|
190
|
+
pass
|
|
191
|
+
|
|
192
|
+
# try to autodetect if all columns are numeric
|
|
193
|
+
# Try to determine if cstrings are strings, filter out non-strings
|
|
194
|
+
cstrings = filter(lambda x: isinstance(x, string_types), colnames)
|
|
195
|
+
# If there is a string, colsnumeric is False, only returns True when all are numbers
|
|
196
|
+
colsnumeric = not len(list(cstrings))
|
|
197
|
+
if colsnumeric:
|
|
198
|
+
# If all column names are numbers, this flag is True, keep behavior unchanged here
|
|
199
|
+
pass
|
|
200
|
+
|
|
201
|
+
# Where each datafield find its value
|
|
202
|
+
# Define a dictionary
|
|
203
|
+
self._colmapping = {}
|
|
204
|
+
|
|
205
|
+
# Build the column mappings to internal fields in advance
|
|
206
|
+
# Iterate through each column
|
|
207
|
+
for datafield in self.getlinealiases():
|
|
208
|
+
# Index where column is located
|
|
209
|
+
defmapping = getattr(self.params, datafield)
|
|
210
|
+
# If column index is number and less than 0, need auto-detection
|
|
211
|
+
if isinstance(defmapping, integer_types) and defmapping < 0:
|
|
212
|
+
# autodetection requested
|
|
213
|
+
for colname in colnames:
|
|
214
|
+
# If column name is string
|
|
215
|
+
if isinstance(colname, string_types):
|
|
216
|
+
# If case-insensitive, compare lowercase equality, if equal means found,
|
|
217
|
+
# otherwise directly compare if equal
|
|
218
|
+
if self.p.nocase:
|
|
219
|
+
found = datafield.lower() == colname.lower()
|
|
220
|
+
else:
|
|
221
|
+
found = datafield == colname
|
|
222
|
+
# If found, map datafield to colname one-to-one, then exit this loop, continue with datafield
|
|
223
|
+
if found:
|
|
224
|
+
self._colmapping[datafield] = colname
|
|
225
|
+
break
|
|
226
|
+
# If searched through df columns and not found, set to None
|
|
227
|
+
if datafield not in self._colmapping:
|
|
228
|
+
# autodetection requested and not found
|
|
229
|
+
self._colmapping[datafield] = None
|
|
230
|
+
continue
|
|
231
|
+
|
|
232
|
+
# If user defined datafield themselves, directly use user's definition
|
|
233
|
+
else:
|
|
234
|
+
# all other cases -- used given index
|
|
235
|
+
self._colmapping[datafield] = defmapping
|
|
236
|
+
|
|
237
|
+
def _resolve_colmapping(self):
|
|
238
|
+
"""Resolve textual column names in self._colmapping to integer indices.
|
|
239
|
+
|
|
240
|
+
Extracted from start(). Honors the ``nocase`` param; a missing column
|
|
241
|
+
falls back to None only when the param default is a negative int,
|
|
242
|
+
otherwise the original ValueError is propagated.
|
|
243
|
+
"""
|
|
244
|
+
# Transform names (valid for .ix) into indices (good for .iloc)
|
|
245
|
+
# If case-insensitive, convert column names to lowercase, if sensitive, keep original
|
|
246
|
+
if self.p.nocase:
|
|
247
|
+
colnames = [x.lower() for x in self.p.dataname.columns.values]
|
|
248
|
+
else:
|
|
249
|
+
colnames = list(self.p.dataname.columns.values)
|
|
250
|
+
|
|
251
|
+
# Iterate through datafield and column names
|
|
252
|
+
for k, v in self._colmapping.items():
|
|
253
|
+
# If column name is None, represents this column is likely datetime
|
|
254
|
+
if v is None:
|
|
255
|
+
continue # special marker for datetime
|
|
256
|
+
# If column name is string, if case-insensitive, convert to lowercase first,
|
|
257
|
+
# if sensitive, ignore, then get column index based on column name
|
|
258
|
+
if isinstance(v, string_types):
|
|
259
|
+
try:
|
|
260
|
+
if self.p.nocase:
|
|
261
|
+
v = colnames.index(v.lower())
|
|
262
|
+
else:
|
|
263
|
+
v = colnames.index(v)
|
|
264
|
+
except ValueError as e:
|
|
265
|
+
defmap = getattr(self.params, k)
|
|
266
|
+
if isinstance(defmap, integer_types) and defmap < 0:
|
|
267
|
+
v = None
|
|
268
|
+
else:
|
|
269
|
+
raise e # let user now something failed
|
|
270
|
+
# If not string, user defined specific integer, directly use user's definition
|
|
271
|
+
self._colmapping[k] = v
|
|
272
|
+
|
|
273
|
+
def start(self):
|
|
274
|
+
"""Start the Pandas data feed.
|
|
275
|
+
|
|
276
|
+
Resets index and converts column names to indices.
|
|
277
|
+
"""
|
|
278
|
+
super().start()
|
|
279
|
+
# Before starting, reset _idx first
|
|
280
|
+
# reset the length with each start
|
|
281
|
+
self._idx = -1
|
|
282
|
+
|
|
283
|
+
# Resolve textual column names in the colmapping into integer indices
|
|
284
|
+
self._resolve_colmapping()
|
|
285
|
+
|
|
286
|
+
df = self.p.dataname
|
|
287
|
+
self._df_len = len(df)
|
|
288
|
+
|
|
289
|
+
linealiases = self.getlinealiases()
|
|
290
|
+
loaditems = []
|
|
291
|
+
for datafield in linealiases:
|
|
292
|
+
if datafield == "datetime":
|
|
293
|
+
continue
|
|
294
|
+
colindex = self._colmapping.get(datafield)
|
|
295
|
+
if colindex is None:
|
|
296
|
+
continue
|
|
297
|
+
loaditems.append((getattr(self.lines, datafield), colindex))
|
|
298
|
+
|
|
299
|
+
self._loaditems = loaditems
|
|
300
|
+
self._coldtime = self._colmapping.get("datetime")
|
|
301
|
+
|
|
302
|
+
self._df_values = None
|
|
303
|
+
try:
|
|
304
|
+
self._df_values = df.to_numpy(copy=False)
|
|
305
|
+
except Exception as e:
|
|
306
|
+
logger.warning("Failed to convert DataFrame to numpy array: %s", e)
|
|
307
|
+
self._df_values = None
|
|
308
|
+
|
|
309
|
+
self._dt_dtnum = None
|
|
310
|
+
try:
|
|
311
|
+
coldtime = self._coldtime
|
|
312
|
+
ts = df.index if coldtime is None else df.iloc[:, coldtime]
|
|
313
|
+
try:
|
|
314
|
+
import numpy as np
|
|
315
|
+
|
|
316
|
+
py_dts = np.array(ts.to_pydatetime())
|
|
317
|
+
except Exception as e1:
|
|
318
|
+
logger.debug("ts.to_pydatetime() failed, trying .dt accessor: %s", e1)
|
|
319
|
+
try:
|
|
320
|
+
import warnings
|
|
321
|
+
|
|
322
|
+
import numpy as np
|
|
323
|
+
|
|
324
|
+
with warnings.catch_warnings():
|
|
325
|
+
warnings.simplefilter("ignore", FutureWarning)
|
|
326
|
+
py_dts = np.array(ts.dt.to_pydatetime())
|
|
327
|
+
except Exception as e2:
|
|
328
|
+
logger.debug(
|
|
329
|
+
"ts.dt.to_pydatetime() failed, falling back to element-wise: %s", e2
|
|
330
|
+
)
|
|
331
|
+
py_dts = [x.to_pydatetime() if hasattr(x, "to_pydatetime") else x for x in ts]
|
|
332
|
+
self._dt_dtnum = [date2num(d) for d in py_dts]
|
|
333
|
+
except Exception as e:
|
|
334
|
+
logger.warning("Failed to pre-compute datetime numbers: %s", e)
|
|
335
|
+
self._dt_dtnum = None
|
|
336
|
+
|
|
337
|
+
def _load(self):
|
|
338
|
+
# Load one row at a time, _idx increments by 1 each time
|
|
339
|
+
self._idx += 1
|
|
340
|
+
# If _idx exceeds data length, return False
|
|
341
|
+
if self._idx >= self._df_len:
|
|
342
|
+
# exhausted all rows
|
|
343
|
+
return False
|
|
344
|
+
|
|
345
|
+
row = self._idx
|
|
346
|
+
values = self._df_values
|
|
347
|
+
loaditems = self._loaditems
|
|
348
|
+
dt_dtnum = self._dt_dtnum
|
|
349
|
+
if values is not None and loaditems is not None and dt_dtnum is not None:
|
|
350
|
+
for line, col in loaditems:
|
|
351
|
+
line[0] = values[row, col]
|
|
352
|
+
|
|
353
|
+
self.lines.datetime[0] = dt_dtnum[row]
|
|
354
|
+
return True
|
|
355
|
+
|
|
356
|
+
df = self.p.dataname
|
|
357
|
+
if loaditems is None:
|
|
358
|
+
for datafield in self.getlinealiases():
|
|
359
|
+
if datafield == "datetime":
|
|
360
|
+
continue
|
|
361
|
+
|
|
362
|
+
colindex = self._colmapping[datafield]
|
|
363
|
+
if colindex is None:
|
|
364
|
+
continue
|
|
365
|
+
|
|
366
|
+
line = getattr(self.lines, datafield)
|
|
367
|
+
line[0] = df.iloc[row, colindex]
|
|
368
|
+
else:
|
|
369
|
+
for line, col in loaditems:
|
|
370
|
+
line[0] = df.iloc[row, col]
|
|
371
|
+
|
|
372
|
+
coldtime = self._coldtime
|
|
373
|
+
if coldtime is None:
|
|
374
|
+
tstamp = df.index[row]
|
|
375
|
+
else:
|
|
376
|
+
tstamp = df.iloc[row, coldtime]
|
|
377
|
+
|
|
378
|
+
dt = tstamp.to_pydatetime() if hasattr(tstamp, "to_pydatetime") else tstamp
|
|
379
|
+
self.lines.datetime[0] = date2num(dt)
|
|
380
|
+
|
|
381
|
+
return True
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Quandl Data Feed Module - Quandl data parsing.
|
|
3
|
+
|
|
4
|
+
.. deprecated::
|
|
5
|
+
Quandl was acquired by Nasdaq and the free API has been sunset.
|
|
6
|
+
Use Nasdaq Data Link or alternative data sources instead.
|
|
7
|
+
This module is retained for backward compatibility but will be
|
|
8
|
+
removed in a future release.
|
|
9
|
+
|
|
10
|
+
Classes:
|
|
11
|
+
QuandlCSV: Parses pre-downloaded Quandl CSV files.
|
|
12
|
+
Quandl: Live Quandl data feed.
|
|
13
|
+
|
|
14
|
+
Example:
|
|
15
|
+
>>> data = bt.feeds.QuandlCSV(dataname='quandl.csv')
|
|
16
|
+
>>> cerebro.adddata(data)
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import collections
|
|
20
|
+
import warnings
|
|
21
|
+
|
|
22
|
+
warnings.warn(
|
|
23
|
+
"backtrader.feeds.quandl is deprecated (Quandl free API sunset). "
|
|
24
|
+
"Consider using Nasdaq Data Link or alternative data sources.",
|
|
25
|
+
DeprecationWarning,
|
|
26
|
+
stacklevel=2,
|
|
27
|
+
)
|
|
28
|
+
import io # noqa: E402
|
|
29
|
+
import itertools # noqa: E402
|
|
30
|
+
from datetime import date, datetime # noqa: E402
|
|
31
|
+
|
|
32
|
+
from .. import feed # noqa: E402
|
|
33
|
+
from ..utils import date2num # noqa: E402
|
|
34
|
+
from ..utils.py3 import urlquote # noqa: E402
|
|
35
|
+
|
|
36
|
+
__all__ = ["QuandlCSV", "Quandl"]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class QuandlCSV(feed.CSVDataBase):
|
|
40
|
+
"""
|
|
41
|
+
Parses pre-downloaded Quandl CSV Data Feeds (or locally generated if they
|
|
42
|
+
comply to the Quandl format)
|
|
43
|
+
|
|
44
|
+
Specific parameters:
|
|
45
|
+
|
|
46
|
+
- ``dataname``: The filename to parse or a file-like object
|
|
47
|
+
|
|
48
|
+
- ``reverse`` (default: ``False``)
|
|
49
|
+
|
|
50
|
+
It is assumed that locally stored files have already been reversed
|
|
51
|
+
during the download process
|
|
52
|
+
|
|
53
|
+
- ``adjclose`` (default: ``True``)
|
|
54
|
+
|
|
55
|
+
Whether to use the dividend/split adjusted close and adjust all
|
|
56
|
+
values according to it.
|
|
57
|
+
|
|
58
|
+
- ``round`` (default: ``False``)
|
|
59
|
+
|
|
60
|
+
Whether to round the values to a specific number of decimals after
|
|
61
|
+
having adjusted the close
|
|
62
|
+
|
|
63
|
+
- ``decimals`` (default: ``2``)
|
|
64
|
+
|
|
65
|
+
Number of decimals to round to
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
_online = False # flag to avoid double reversal
|
|
69
|
+
|
|
70
|
+
params = (
|
|
71
|
+
("reverse", False),
|
|
72
|
+
("adjclose", True),
|
|
73
|
+
("round", False),
|
|
74
|
+
("decimals", 2),
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
def start(self):
|
|
78
|
+
"""Start the Quandl CSV data feed.
|
|
79
|
+
|
|
80
|
+
Reverses data if needed for correct chronological order.
|
|
81
|
+
"""
|
|
82
|
+
super().start()
|
|
83
|
+
|
|
84
|
+
if not self.params.reverse:
|
|
85
|
+
return
|
|
86
|
+
if self._online:
|
|
87
|
+
return # revers is True but also online, managed with order = asc
|
|
88
|
+
|
|
89
|
+
# Quandl data can be in reverse order -> reverse
|
|
90
|
+
dq: collections.deque = collections.deque()
|
|
91
|
+
for line in self.f:
|
|
92
|
+
dq.appendleft(line)
|
|
93
|
+
|
|
94
|
+
f = io.StringIO(newline=None)
|
|
95
|
+
f.writelines(dq)
|
|
96
|
+
f.seek(0)
|
|
97
|
+
self.f.close()
|
|
98
|
+
self.f = f
|
|
99
|
+
|
|
100
|
+
def _loadline(self, linetokens):
|
|
101
|
+
i = itertools.count(0)
|
|
102
|
+
|
|
103
|
+
dttxt = linetokens[next(i)] # YYYY-MM-DD
|
|
104
|
+
dt = date(int(dttxt[0:4]), int(dttxt[5:7]), int(dttxt[8:10]))
|
|
105
|
+
dtnum = date2num(datetime.combine(dt, self.p.sessionend))
|
|
106
|
+
|
|
107
|
+
self.lines.datetime[0] = dtnum
|
|
108
|
+
if self.p.adjclose:
|
|
109
|
+
for _ in range(7):
|
|
110
|
+
next(i) # skip ohlcv, ex-dividend, split ratio
|
|
111
|
+
|
|
112
|
+
o = float(linetokens[next(i)])
|
|
113
|
+
h = float(linetokens[next(i)])
|
|
114
|
+
low = float(linetokens[next(i)])
|
|
115
|
+
c = float(linetokens[next(i)])
|
|
116
|
+
v = float(linetokens[next(i)])
|
|
117
|
+
self.lines.openinterest[0] = 0.0
|
|
118
|
+
|
|
119
|
+
if self.p.round:
|
|
120
|
+
decimals = self.p.decimals
|
|
121
|
+
o = round(o, decimals)
|
|
122
|
+
h = round(h, decimals)
|
|
123
|
+
low = round(low, decimals)
|
|
124
|
+
c = round(c, decimals)
|
|
125
|
+
v = round(v, decimals)
|
|
126
|
+
|
|
127
|
+
self.lines.open[0] = o
|
|
128
|
+
self.lines.high[0] = h
|
|
129
|
+
self.lines.low[0] = low
|
|
130
|
+
self.lines.close[0] = c
|
|
131
|
+
self.lines.volume[0] = v
|
|
132
|
+
|
|
133
|
+
return True
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class Quandl(QuandlCSV):
|
|
137
|
+
"""
|
|
138
|
+
Executes a direct download of data from Quandl servers for the given time
|
|
139
|
+
range.
|
|
140
|
+
|
|
141
|
+
Specific parameters (or specific meaning):
|
|
142
|
+
|
|
143
|
+
- ``dataname``
|
|
144
|
+
|
|
145
|
+
The ticker to download ('YHOO', for example)
|
|
146
|
+
|
|
147
|
+
- ``baseurl``
|
|
148
|
+
|
|
149
|
+
The server url. Someone might decide to open a Quandl compatible
|
|
150
|
+
service in the future.
|
|
151
|
+
|
|
152
|
+
- ``proxies``
|
|
153
|
+
|
|
154
|
+
A dict indicating which proxy to go through for the download as in
|
|
155
|
+
{'http': 'http://myproxy.com'} or {'http': 'http://127.0.0.1:8080'}
|
|
156
|
+
|
|
157
|
+
- ``buffered``
|
|
158
|
+
|
|
159
|
+
If True, the entire socket connection will be buffered locally before
|
|
160
|
+
parsing starts.
|
|
161
|
+
|
|
162
|
+
- ``reverse``
|
|
163
|
+
|
|
164
|
+
Quandl returns the value in descending order (newest first). If this is
|
|
165
|
+
``True`` (the default), the request will tell Quandl to return in
|
|
166
|
+
ascending (oldest to newest) format
|
|
167
|
+
|
|
168
|
+
- ``adjclose``
|
|
169
|
+
|
|
170
|
+
Whether to use the dividend/split adjusted close and adjust all values
|
|
171
|
+
according to it.
|
|
172
|
+
|
|
173
|
+
- ``apikey``
|
|
174
|
+
|
|
175
|
+
Apikey identification in case it may be needed
|
|
176
|
+
|
|
177
|
+
- ``dataset``
|
|
178
|
+
|
|
179
|
+
String identifying the dataset to query. Defaults to ``WIKI``
|
|
180
|
+
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
_online = True # flag to avoid double reversal
|
|
184
|
+
|
|
185
|
+
params: tuple = (
|
|
186
|
+
("baseurl", "https://www.quandl.com/api/v3/datasets"),
|
|
187
|
+
("proxies", {}),
|
|
188
|
+
("buffered", True),
|
|
189
|
+
("reverse", True),
|
|
190
|
+
("apikey", None),
|
|
191
|
+
("dataset", "WIKI"),
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
def __init__(self):
|
|
195
|
+
"""Initialize the Quandl data feed.
|
|
196
|
+
|
|
197
|
+
Sets up error tracking for data downloads.
|
|
198
|
+
"""
|
|
199
|
+
self.error = None
|
|
200
|
+
|
|
201
|
+
def start(self):
|
|
202
|
+
"""Start the Quandl data feed and download data.
|
|
203
|
+
|
|
204
|
+
Constructs URL with parameters and fetches data from Quandl API.
|
|
205
|
+
"""
|
|
206
|
+
self.error = None
|
|
207
|
+
|
|
208
|
+
url = f"{self.p.baseurl}/{self.p.dataset}/{urlquote(self.p.dataname)}.csv"
|
|
209
|
+
|
|
210
|
+
urlargs = []
|
|
211
|
+
if self.p.reverse:
|
|
212
|
+
urlargs.append("order=asc")
|
|
213
|
+
|
|
214
|
+
if self.p.apikey is not None:
|
|
215
|
+
urlargs.append(f"api_key={self.p.apikey}")
|
|
216
|
+
|
|
217
|
+
if self.p.fromdate:
|
|
218
|
+
dtxt = self.p.fromdate.strftime("%Y-%m-%d")
|
|
219
|
+
urlargs.append(f"start_date={dtxt}")
|
|
220
|
+
|
|
221
|
+
if self.p.todate:
|
|
222
|
+
dtxt = self.p.todate.strftime("%Y-%m-%d")
|
|
223
|
+
urlargs.append(f"end_date={dtxt}")
|
|
224
|
+
|
|
225
|
+
if urlargs:
|
|
226
|
+
url += "?" + "&".join(urlargs)
|
|
227
|
+
|
|
228
|
+
from ..utils.py3 import ProxyHandler, build_opener, install_opener, urlopen
|
|
229
|
+
|
|
230
|
+
if self.p.proxies:
|
|
231
|
+
proxy = ProxyHandler(self.p.proxies)
|
|
232
|
+
opener = build_opener(proxy)
|
|
233
|
+
install_opener(opener)
|
|
234
|
+
|
|
235
|
+
try:
|
|
236
|
+
datafile = urlopen(url)
|
|
237
|
+
except OSError as e:
|
|
238
|
+
self.error = str(e)
|
|
239
|
+
# leave us empty
|
|
240
|
+
return
|
|
241
|
+
|
|
242
|
+
if datafile.headers["Content-Type"] != "text/csv":
|
|
243
|
+
self.error = "Wrong content type: %s" % datafile.headers
|
|
244
|
+
return # HTML returned? wrong url?
|
|
245
|
+
|
|
246
|
+
if self.params.buffered:
|
|
247
|
+
# buffer everything from the socket into a local buffer
|
|
248
|
+
f = io.StringIO(datafile.read().decode("utf-8"), newline=None)
|
|
249
|
+
datafile.close()
|
|
250
|
+
else:
|
|
251
|
+
f = datafile
|
|
252
|
+
|
|
253
|
+
self.f = f
|
|
254
|
+
|
|
255
|
+
# Prepared a "path" file - CSV Parser can take over
|
|
256
|
+
super().start()
|