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,534 @@
|
|
|
1
|
+
"""Sharpe Ratio Statistics Module - Advanced Sharpe ratio calculations.
|
|
2
|
+
|
|
3
|
+
This module provides functions for calculating Sharpe ratio statistics
|
|
4
|
+
including estimated, probabilistic, and defecto Sharpe ratios, along
|
|
5
|
+
with their confidence intervals and significance tests.
|
|
6
|
+
|
|
7
|
+
Functions:
|
|
8
|
+
estimated_sharpe_ratio: Calculate basic Sharpe ratio.
|
|
9
|
+
ann_estimated_sharpe_ratio: Calculate annualized Sharpe ratio.
|
|
10
|
+
estimated_sharpe_ratio_stdev: Standard deviation of Sharpe estimation.
|
|
11
|
+
probabilistic_sharpe_ratio: PSR calculation.
|
|
12
|
+
min_track_record_length: Minimum track record for significance.
|
|
13
|
+
sharpe_ratio_defacto: Defacto Sharpe ratio calculation.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import numpy as np
|
|
17
|
+
import pandas as pd
|
|
18
|
+
from scipy import stats as scipy_stats
|
|
19
|
+
|
|
20
|
+
from ..utils.log_message import get_logger
|
|
21
|
+
|
|
22
|
+
logger = get_logger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _is_integer_like(value):
|
|
26
|
+
try:
|
|
27
|
+
return (
|
|
28
|
+
not isinstance(value, (bool, np.bool_))
|
|
29
|
+
and np.isscalar(value)
|
|
30
|
+
and np.isfinite(value)
|
|
31
|
+
and float(value).is_integer()
|
|
32
|
+
)
|
|
33
|
+
except (TypeError, ValueError):
|
|
34
|
+
return False
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _is_finite_value(value):
|
|
38
|
+
try:
|
|
39
|
+
return bool(np.all(np.isfinite(np.asarray(value))))
|
|
40
|
+
except (TypeError, ValueError):
|
|
41
|
+
return False
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _average_upper_triangle_correlation(trials_returns):
|
|
45
|
+
"""Compute the mean pairwise correlation across trial return columns."""
|
|
46
|
+
corr_matrix = trials_returns.corr()
|
|
47
|
+
if corr_matrix.empty:
|
|
48
|
+
return 0.0
|
|
49
|
+
|
|
50
|
+
upper = corr_matrix.values[np.triu_indices_from(corr_matrix.values, 1)]
|
|
51
|
+
if upper.size == 0:
|
|
52
|
+
return 0.0
|
|
53
|
+
|
|
54
|
+
avg_corr = np.nanmean(upper)
|
|
55
|
+
if not np.isfinite(avg_corr):
|
|
56
|
+
return 0.0
|
|
57
|
+
|
|
58
|
+
return float(avg_corr)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def estimated_sharpe_ratio(returns):
|
|
62
|
+
"""
|
|
63
|
+
Calculate the estimated sharpe ratio (risk_free=0).
|
|
64
|
+
|
|
65
|
+
Parameters
|
|
66
|
+
----------
|
|
67
|
+
returns: `np.array`, pd.Series, pd.DataFrame
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
-------
|
|
71
|
+
float, pd.Series
|
|
72
|
+
"""
|
|
73
|
+
if returns is None:
|
|
74
|
+
raise ValueError("estimated_sharpe_ratio requires returns")
|
|
75
|
+
if len(returns) <= 1:
|
|
76
|
+
raise ValueError("estimated_sharpe_ratio requires at least 2 return samples")
|
|
77
|
+
|
|
78
|
+
return returns.mean() / returns.std(ddof=1)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def ann_estimated_sharpe_ratio(returns=None, periods=261, *, sr=None):
|
|
82
|
+
"""
|
|
83
|
+
Calculate the annualized estimated sharpe ratio (risk_free=0).
|
|
84
|
+
|
|
85
|
+
Parameters
|
|
86
|
+
----------
|
|
87
|
+
returns: `np.array`, pd.Series, pd.DataFrame
|
|
88
|
+
|
|
89
|
+
periods: int
|
|
90
|
+
How many items in `returns` complete a Year.
|
|
91
|
+
If returns are daily: 261, weekly: 52, monthly: 12, ...
|
|
92
|
+
|
|
93
|
+
sr: float, `np.array`, pd.Series, pd.DataFrame
|
|
94
|
+
Sharpe ratio to be annualized, its frequency must be coherent with `periods`
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
float, pd.Series
|
|
99
|
+
"""
|
|
100
|
+
if returns is None and sr is None:
|
|
101
|
+
raise ValueError("ann_estimated_sharpe_ratio requires returns or sr")
|
|
102
|
+
if not _is_integer_like(periods):
|
|
103
|
+
raise ValueError("ann_estimated_sharpe_ratio requires integer periods")
|
|
104
|
+
periods = int(periods)
|
|
105
|
+
if periods <= 0:
|
|
106
|
+
raise ValueError("ann_estimated_sharpe_ratio requires periods > 0")
|
|
107
|
+
if sr is not None and not _is_finite_value(sr):
|
|
108
|
+
raise ValueError("ann_estimated_sharpe_ratio requires finite sr")
|
|
109
|
+
|
|
110
|
+
if sr is None:
|
|
111
|
+
if len(returns) <= 1:
|
|
112
|
+
raise ValueError(
|
|
113
|
+
"ann_estimated_sharpe_ratio requires at least 2 return samples when sr is None"
|
|
114
|
+
)
|
|
115
|
+
sr = estimated_sharpe_ratio(returns)
|
|
116
|
+
sr = sr * np.sqrt(periods)
|
|
117
|
+
return sr
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _validate_srstdev_params(_returns, n, skew, kurtosis, sr):
|
|
121
|
+
"""Validate/normalize estimated_sharpe_ratio_stdev inputs; return int n.
|
|
122
|
+
|
|
123
|
+
Resolves n from _returns when not given, enforces integer n > 1 and finite
|
|
124
|
+
skew/kurtosis/sr. Extracted from estimated_sharpe_ratio_stdev.
|
|
125
|
+
"""
|
|
126
|
+
if _returns is not None and n is None:
|
|
127
|
+
n = len(_returns)
|
|
128
|
+
if not _is_integer_like(n):
|
|
129
|
+
raise ValueError("estimated_sharpe_ratio_stdev requires integer n")
|
|
130
|
+
n = int(n)
|
|
131
|
+
if n <= 1:
|
|
132
|
+
raise ValueError("estimated_sharpe_ratio_stdev requires n > 1")
|
|
133
|
+
if skew is not None and not _is_finite_value(skew):
|
|
134
|
+
raise ValueError("estimated_sharpe_ratio_stdev requires finite skew")
|
|
135
|
+
if kurtosis is not None and not _is_finite_value(kurtosis):
|
|
136
|
+
raise ValueError("estimated_sharpe_ratio_stdev requires finite kurtosis")
|
|
137
|
+
if sr is not None and not _is_finite_value(sr):
|
|
138
|
+
raise ValueError("estimated_sharpe_ratio_stdev requires finite sr")
|
|
139
|
+
return n
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def estimated_sharpe_ratio_stdev(returns=None, *, n=None, skew=None, kurtosis=None, sr=None):
|
|
143
|
+
"""
|
|
144
|
+
Calculate the standard deviation of the sharpe ratio estimation.
|
|
145
|
+
|
|
146
|
+
Parameters
|
|
147
|
+
----------
|
|
148
|
+
returns: `np.array`, pd.Series, pd.DataFrame
|
|
149
|
+
If no `returns` are passed it is mandatory to pass the other four parameters.
|
|
150
|
+
|
|
151
|
+
n: int
|
|
152
|
+
Number of returns samples used for calculating `skew`, `kurtosis` and `sr`.
|
|
153
|
+
|
|
154
|
+
skew: float, `np.array`, pd.Series, pd.DataFrame
|
|
155
|
+
The third moment expressed in the same frequency as the other parameters.
|
|
156
|
+
`Skew`=0 for normal returns.
|
|
157
|
+
|
|
158
|
+
kurtosis: float, `np.array`, pd.Series, pd.DataFrame
|
|
159
|
+
The fourth moment expressed in the same frequency as the other parameters.
|
|
160
|
+
`Kurtosis`=3 for normal returns.
|
|
161
|
+
|
|
162
|
+
sr: float, `np.array`, pd.Series, pd.DataFrame
|
|
163
|
+
Sharpe ratio expressed in the same frequency as the other parameters.
|
|
164
|
+
|
|
165
|
+
Returns
|
|
166
|
+
-------
|
|
167
|
+
float, pd.Series
|
|
168
|
+
|
|
169
|
+
Notes
|
|
170
|
+
-----
|
|
171
|
+
This formula generalizes for both normal and non-normal returns.
|
|
172
|
+
https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1821643
|
|
173
|
+
"""
|
|
174
|
+
# if type(returns) != pd.DataFrame:
|
|
175
|
+
# _returns = pd.DataFrame(returns)
|
|
176
|
+
# else:
|
|
177
|
+
# _returns = returns.copy()
|
|
178
|
+
|
|
179
|
+
if returns is None:
|
|
180
|
+
if any(param is None for param in (n, skew, kurtosis, sr)):
|
|
181
|
+
raise ValueError(
|
|
182
|
+
"estimated_sharpe_ratio_stdev requires n, skew, kurtosis, and sr when returns is None"
|
|
183
|
+
)
|
|
184
|
+
_returns = None
|
|
185
|
+
elif isinstance(returns, pd.DataFrame):
|
|
186
|
+
_returns = pd.DataFrame(returns)
|
|
187
|
+
else:
|
|
188
|
+
_returns = returns.copy()
|
|
189
|
+
|
|
190
|
+
n = _validate_srstdev_params(_returns, n, skew, kurtosis, sr)
|
|
191
|
+
|
|
192
|
+
if _returns is not None and skew is None:
|
|
193
|
+
skew_values = scipy_stats.skew(_returns)
|
|
194
|
+
if isinstance(_returns, pd.DataFrame):
|
|
195
|
+
skew = pd.Series(skew_values, index=_returns.columns)
|
|
196
|
+
else:
|
|
197
|
+
skew = skew_values
|
|
198
|
+
if _returns is not None and kurtosis is None:
|
|
199
|
+
kurtosis_values = scipy_stats.kurtosis(_returns, fisher=False)
|
|
200
|
+
if isinstance(_returns, pd.DataFrame):
|
|
201
|
+
kurtosis = pd.Series(kurtosis_values, index=_returns.columns)
|
|
202
|
+
else:
|
|
203
|
+
kurtosis = kurtosis_values
|
|
204
|
+
if _returns is not None and sr is None:
|
|
205
|
+
sr = estimated_sharpe_ratio(_returns)
|
|
206
|
+
|
|
207
|
+
sr_std = np.sqrt((1 + (0.5 * sr**2) - (skew * sr) + (((kurtosis - 3) / 4) * sr**2)) / (n - 1))
|
|
208
|
+
|
|
209
|
+
if isinstance(returns, pd.DataFrame):
|
|
210
|
+
sr_std = pd.Series(sr_std, index=returns.columns)
|
|
211
|
+
elif type(sr_std) not in (float, np.float64, pd.DataFrame):
|
|
212
|
+
sr_std = sr_std.values[0]
|
|
213
|
+
|
|
214
|
+
return sr_std
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def probabilistic_sharpe_ratio(returns=None, sr_benchmark=0.0, *, sr=None, sr_std=None):
|
|
218
|
+
"""
|
|
219
|
+
Calculate the Probabilistic Sharpe Ratio (PSR).
|
|
220
|
+
|
|
221
|
+
Parameters
|
|
222
|
+
----------
|
|
223
|
+
returns: `np.array`, pd.Series, pd.DataFrame
|
|
224
|
+
If no `returns` are passed it is mandatory to pass a `sr` and `sr_std`.
|
|
225
|
+
|
|
226
|
+
sr_benchmark: float
|
|
227
|
+
Benchmark sharpe ratio expressed in the same frequency as the other parameters.
|
|
228
|
+
By default, set to zero (comparing against no investment skill).
|
|
229
|
+
|
|
230
|
+
sr: float, `np.array`, pd.Series, pd.DataFrame
|
|
231
|
+
Sharpe ratio expressed in the same frequency as the other parameters.
|
|
232
|
+
|
|
233
|
+
sr_std: float, `np.array`, pd.Series, pd.DataFrame
|
|
234
|
+
Standard deviation fo the Estimated sharpe ratio,
|
|
235
|
+
expressed in the same frequency as the other parameters.
|
|
236
|
+
|
|
237
|
+
Returns
|
|
238
|
+
-------
|
|
239
|
+
float, pd.Series
|
|
240
|
+
|
|
241
|
+
Notes
|
|
242
|
+
-----
|
|
243
|
+
PSR(SR*) = probability that SR^ > SR*
|
|
244
|
+
SR^ = sharpe ratio estimated with `returns`, or `sr`
|
|
245
|
+
SR* = `sr_benchmark`
|
|
246
|
+
|
|
247
|
+
https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1821643
|
|
248
|
+
"""
|
|
249
|
+
if returns is None and any(param is None for param in (sr, sr_std)):
|
|
250
|
+
raise ValueError("probabilistic_sharpe_ratio requires sr and sr_std when returns is None")
|
|
251
|
+
if sr is not None and not _is_finite_value(sr):
|
|
252
|
+
raise ValueError("probabilistic_sharpe_ratio requires finite sr")
|
|
253
|
+
if not _is_finite_value(sr_benchmark):
|
|
254
|
+
raise ValueError("probabilistic_sharpe_ratio requires finite sr_benchmark")
|
|
255
|
+
|
|
256
|
+
if sr is None:
|
|
257
|
+
sr = estimated_sharpe_ratio(returns)
|
|
258
|
+
if sr_std is None:
|
|
259
|
+
sr_std = estimated_sharpe_ratio_stdev(returns, sr=sr)
|
|
260
|
+
if np.any(~np.isfinite(np.asarray(sr_std))) or np.any(np.asarray(sr_std) <= 0):
|
|
261
|
+
raise ValueError("probabilistic_sharpe_ratio requires finite sr_std > 0")
|
|
262
|
+
|
|
263
|
+
psr = scipy_stats.norm.cdf((sr - sr_benchmark) / sr_std)
|
|
264
|
+
|
|
265
|
+
if isinstance(returns, pd.DataFrame):
|
|
266
|
+
psr = pd.Series(psr, index=returns.columns)
|
|
267
|
+
elif type(psr) not in (float, np.float64):
|
|
268
|
+
psr = psr.iloc[0] if isinstance(psr, pd.Series) else psr[0]
|
|
269
|
+
|
|
270
|
+
return psr
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def min_track_record_length(
|
|
274
|
+
returns=None, sr_benchmark=0.0, prob=0.95, *, n=None, sr=None, sr_std=None
|
|
275
|
+
):
|
|
276
|
+
"""
|
|
277
|
+
Calculate the MIn Track Record Length (minTRL).
|
|
278
|
+
|
|
279
|
+
Parameters
|
|
280
|
+
----------
|
|
281
|
+
returns: `np.array`, pd.Series, pd.DataFrame
|
|
282
|
+
If no `returns` are passed it is mandatory to pass a `sr` and `sr_std`.
|
|
283
|
+
|
|
284
|
+
sr_benchmark: float
|
|
285
|
+
Benchmark sharpe ratio expressed in the same frequency as the other parameters.
|
|
286
|
+
By default, set to zero (comparing against no investment skill).
|
|
287
|
+
|
|
288
|
+
prob: float
|
|
289
|
+
Confidence level used for calculating the minTRL.
|
|
290
|
+
Between 0 and 1, by default=0.95
|
|
291
|
+
|
|
292
|
+
n: int
|
|
293
|
+
Number of returns samples used for calculating `sr` and `sr_std`.
|
|
294
|
+
|
|
295
|
+
sr: float, `np.array`, pd.Series, pd.DataFrame
|
|
296
|
+
Sharpe ratio expressed in the same frequency as the other parameters.
|
|
297
|
+
|
|
298
|
+
sr_std: float, `np.array`, pd.Series, pd.DataFrame
|
|
299
|
+
Standard deviation fo the Estimated sharpe ratio,
|
|
300
|
+
expressed in the same frequency as the other parameters.
|
|
301
|
+
|
|
302
|
+
Returns
|
|
303
|
+
-------
|
|
304
|
+
float, pd.Series
|
|
305
|
+
|
|
306
|
+
Notes
|
|
307
|
+
-----
|
|
308
|
+
minTRL = minimum of returns/samples needed (with same SR and SR_STD) to accomplish a PSR(SR*) > `prob`
|
|
309
|
+
PSR(SR*) = probability that SR^ > SR*
|
|
310
|
+
SR^ = sharpe ratio estimated with `returns`, or `sr`
|
|
311
|
+
SR* = `sr_benchmark`
|
|
312
|
+
|
|
313
|
+
https://papers.ssrn.com/sol3/papers.cfm?abstract_id=1821643
|
|
314
|
+
"""
|
|
315
|
+
if returns is None and any(param is None for param in (n, sr, sr_std)):
|
|
316
|
+
raise ValueError("min_track_record_length requires n, sr, and sr_std when returns is None")
|
|
317
|
+
if not 0 < prob < 1:
|
|
318
|
+
raise ValueError("min_track_record_length requires 0 < prob < 1")
|
|
319
|
+
if not _is_finite_value(sr_benchmark):
|
|
320
|
+
raise ValueError("min_track_record_length requires finite sr_benchmark")
|
|
321
|
+
|
|
322
|
+
if n is None:
|
|
323
|
+
n = len(returns)
|
|
324
|
+
if not _is_integer_like(n):
|
|
325
|
+
raise ValueError("min_track_record_length requires integer n")
|
|
326
|
+
n = int(n)
|
|
327
|
+
if n <= 1:
|
|
328
|
+
raise ValueError("min_track_record_length requires n > 1")
|
|
329
|
+
if sr is not None and not _is_finite_value(sr):
|
|
330
|
+
raise ValueError("min_track_record_length requires finite sr")
|
|
331
|
+
if sr is None:
|
|
332
|
+
sr = estimated_sharpe_ratio(returns)
|
|
333
|
+
if sr_std is None:
|
|
334
|
+
sr_std = estimated_sharpe_ratio_stdev(returns, sr=sr)
|
|
335
|
+
if np.any(~np.isfinite(np.asarray(sr_std))) or np.any(np.asarray(sr_std) <= 0):
|
|
336
|
+
raise ValueError("min_track_record_length requires finite sr_std > 0")
|
|
337
|
+
|
|
338
|
+
min_trl = 1 + (sr_std**2 * (n - 1)) * (scipy_stats.norm.ppf(prob) / (sr - sr_benchmark)) ** 2
|
|
339
|
+
|
|
340
|
+
if isinstance(returns, pd.DataFrame):
|
|
341
|
+
min_trl = pd.Series(min_trl, index=returns.columns)
|
|
342
|
+
elif type(min_trl) not in (float, np.float64):
|
|
343
|
+
min_trl = min_trl.iloc[0] if isinstance(min_trl, pd.Series) else min_trl[0]
|
|
344
|
+
|
|
345
|
+
return min_trl
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def num_independent_trials(trials_returns=None, *, m=None, p=None):
|
|
349
|
+
"""
|
|
350
|
+
Calculate the number of independent trials.
|
|
351
|
+
|
|
352
|
+
Parameters
|
|
353
|
+
----------
|
|
354
|
+
trials_returns: pd.DataFrame
|
|
355
|
+
All trials returns, not only the independent trials.
|
|
356
|
+
|
|
357
|
+
m: int
|
|
358
|
+
Number of total trials.
|
|
359
|
+
|
|
360
|
+
p: float
|
|
361
|
+
Average correlation between all the trials.
|
|
362
|
+
|
|
363
|
+
Returns
|
|
364
|
+
-------
|
|
365
|
+
int
|
|
366
|
+
"""
|
|
367
|
+
if trials_returns is None and any(param is None for param in (m, p)):
|
|
368
|
+
raise ValueError(
|
|
369
|
+
"num_independent_trials requires trials_returns when m or p is not provided"
|
|
370
|
+
)
|
|
371
|
+
if m is not None and not _is_integer_like(m):
|
|
372
|
+
raise ValueError("num_independent_trials requires integer m")
|
|
373
|
+
if m is not None:
|
|
374
|
+
m = int(m)
|
|
375
|
+
if m is not None and m <= 0:
|
|
376
|
+
raise ValueError("num_independent_trials requires m > 0")
|
|
377
|
+
|
|
378
|
+
if m is None:
|
|
379
|
+
m = trials_returns.shape[1]
|
|
380
|
+
|
|
381
|
+
if p is None:
|
|
382
|
+
p = _average_upper_triangle_correlation(trials_returns)
|
|
383
|
+
else:
|
|
384
|
+
if isinstance(p, (bool, np.bool_)) or not np.isscalar(p):
|
|
385
|
+
raise ValueError("num_independent_trials requires scalar p")
|
|
386
|
+
try:
|
|
387
|
+
p = float(p)
|
|
388
|
+
except (TypeError, ValueError):
|
|
389
|
+
logger.error("sharpe_ratio_stats:387 re-raising TypeError,ValueError", exc_info=True)
|
|
390
|
+
raise ValueError("num_independent_trials requires scalar p") from None
|
|
391
|
+
if not np.isfinite(p):
|
|
392
|
+
p = 0.0
|
|
393
|
+
elif not -1 <= p <= 1:
|
|
394
|
+
raise ValueError("num_independent_trials requires -1 <= p <= 1")
|
|
395
|
+
|
|
396
|
+
n = p + (1 - p) * m
|
|
397
|
+
|
|
398
|
+
n = int(n) + 1 # round up
|
|
399
|
+
|
|
400
|
+
return n
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def expected_maximum_sr(
|
|
404
|
+
trials_returns=None, expected_mean_sr=0.0, *, independent_trials=None, trials_sr_std=None
|
|
405
|
+
):
|
|
406
|
+
"""
|
|
407
|
+
Compute the expected maximum Sharpe ratio (Analytically)
|
|
408
|
+
|
|
409
|
+
Parameters
|
|
410
|
+
----------
|
|
411
|
+
trials_returns: pd.DataFrame
|
|
412
|
+
All trials returns, not only the independent trials.
|
|
413
|
+
|
|
414
|
+
expected_mean_sr: float
|
|
415
|
+
Expected mean SR, usually 0. We assume that random startegies will have a mean SR of 0,
|
|
416
|
+
expressed in the same frequency as the other parameters.
|
|
417
|
+
|
|
418
|
+
independent_trials: int
|
|
419
|
+
Number of independent trials must be between 1 and `trials_returns.shape[1]`
|
|
420
|
+
|
|
421
|
+
trials_sr_std: float
|
|
422
|
+
Standard deviation for the Estimated sharpe ratios of all trials,
|
|
423
|
+
expressed in the same frequency as the other parameters.
|
|
424
|
+
|
|
425
|
+
Returns
|
|
426
|
+
-------
|
|
427
|
+
float
|
|
428
|
+
"""
|
|
429
|
+
emc = 0.5772156649 # Euler-Mascheroni constant
|
|
430
|
+
if not _is_finite_value(expected_mean_sr):
|
|
431
|
+
raise ValueError("expected_maximum_sr requires finite expected_mean_sr")
|
|
432
|
+
|
|
433
|
+
if independent_trials is None:
|
|
434
|
+
if trials_returns is None:
|
|
435
|
+
raise ValueError("expected_maximum_sr requires trials_returns or independent_trials")
|
|
436
|
+
independent_trials = num_independent_trials(trials_returns)
|
|
437
|
+
|
|
438
|
+
if not _is_integer_like(independent_trials):
|
|
439
|
+
raise ValueError("expected_maximum_sr requires integer independent_trials")
|
|
440
|
+
independent_trials = int(independent_trials)
|
|
441
|
+
if independent_trials < 1:
|
|
442
|
+
raise ValueError("expected_maximum_sr requires independent_trials >= 1")
|
|
443
|
+
if trials_returns is not None and independent_trials > trials_returns.shape[1]:
|
|
444
|
+
raise ValueError(
|
|
445
|
+
"expected_maximum_sr requires independent_trials <= number of trial return columns"
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
if independent_trials <= 1:
|
|
449
|
+
return expected_mean_sr
|
|
450
|
+
|
|
451
|
+
if trials_sr_std is None:
|
|
452
|
+
if trials_returns is None:
|
|
453
|
+
raise ValueError(
|
|
454
|
+
"expected_maximum_sr requires trials_returns or trials_sr_std when independent_trials > 1"
|
|
455
|
+
)
|
|
456
|
+
srs = estimated_sharpe_ratio(trials_returns)
|
|
457
|
+
trials_sr_std = srs.std()
|
|
458
|
+
if np.any(np.isfinite(np.asarray(trials_sr_std)) & (np.asarray(trials_sr_std) < 0)):
|
|
459
|
+
raise ValueError("expected_maximum_sr requires trials_sr_std >= 0")
|
|
460
|
+
|
|
461
|
+
if not np.isfinite(trials_sr_std):
|
|
462
|
+
return expected_mean_sr
|
|
463
|
+
|
|
464
|
+
max_z = (1 - emc) * scipy_stats.norm.ppf(
|
|
465
|
+
1 - 1.0 / independent_trials
|
|
466
|
+
) + emc * scipy_stats.norm.ppf(1 - 1.0 / (independent_trials * np.e))
|
|
467
|
+
expected_max_sr = expected_mean_sr + (trials_sr_std * max_z)
|
|
468
|
+
|
|
469
|
+
return expected_max_sr
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
def deflated_sharpe_ratio(
|
|
473
|
+
trials_returns=None,
|
|
474
|
+
returns_selected=None,
|
|
475
|
+
expected_mean_sr=0.0,
|
|
476
|
+
independent_trials=10,
|
|
477
|
+
expected_max_sr=None,
|
|
478
|
+
):
|
|
479
|
+
"""
|
|
480
|
+
Calculate the Deflated Sharpe Ratio (PSR).
|
|
481
|
+
|
|
482
|
+
Parameters
|
|
483
|
+
----------
|
|
484
|
+
trials_returns: pd.DataFrame
|
|
485
|
+
All trials returns, not only the independent trials.
|
|
486
|
+
|
|
487
|
+
returns_selected: pd.Series
|
|
488
|
+
|
|
489
|
+
expected_mean_sr: float
|
|
490
|
+
Expected mean SR, usually 0. We assume that random startegies will have a mean SR of 0,
|
|
491
|
+
expressed in the same frequency as the other parameters.
|
|
492
|
+
|
|
493
|
+
expected_max_sr: float
|
|
494
|
+
The expected maximum sharpe ratio expected after running all the trials,
|
|
495
|
+
expressed in the same frequency as the other parameters.
|
|
496
|
+
independent_trials: int
|
|
497
|
+
|
|
498
|
+
Returns
|
|
499
|
+
-------
|
|
500
|
+
float
|
|
501
|
+
|
|
502
|
+
Notes
|
|
503
|
+
-----
|
|
504
|
+
DFS = PSR(SR⁰) = probability that SR^ > SR⁰
|
|
505
|
+
SR^ = sharpe ratio estimated with `returns`, or `sr`
|
|
506
|
+
SR⁰ = `max_expected_sr`
|
|
507
|
+
|
|
508
|
+
https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2460551
|
|
509
|
+
"""
|
|
510
|
+
if returns_selected is None:
|
|
511
|
+
raise ValueError("deflated_sharpe_ratio requires returns_selected")
|
|
512
|
+
if expected_max_sr is None and trials_returns is None:
|
|
513
|
+
raise ValueError(
|
|
514
|
+
"deflated_sharpe_ratio requires trials_returns when expected_max_sr is None"
|
|
515
|
+
)
|
|
516
|
+
if expected_max_sr is not None and not _is_finite_value(expected_max_sr):
|
|
517
|
+
raise ValueError("deflated_sharpe_ratio requires finite expected_max_sr")
|
|
518
|
+
|
|
519
|
+
if expected_max_sr is None:
|
|
520
|
+
effective_independent_trials = independent_trials
|
|
521
|
+
if trials_returns is not None:
|
|
522
|
+
effective_independent_trials = min(
|
|
523
|
+
effective_independent_trials, trials_returns.shape[1]
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
expected_max_sr = expected_maximum_sr(
|
|
527
|
+
trials_returns=trials_returns,
|
|
528
|
+
expected_mean_sr=expected_mean_sr,
|
|
529
|
+
independent_trials=effective_independent_trials,
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
dsr = probabilistic_sharpe_ratio(returns=returns_selected, sr_benchmark=expected_max_sr)
|
|
533
|
+
|
|
534
|
+
return dsr
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""SQN Analyzer Module - System Quality Number calculation.
|
|
3
|
+
|
|
4
|
+
This module provides the SQN (System Quality Number) analyzer, defined
|
|
5
|
+
by Van K. Tharp to categorize trading systems.
|
|
6
|
+
|
|
7
|
+
Classes:
|
|
8
|
+
SQN: Analyzer that calculates System Quality Number.
|
|
9
|
+
|
|
10
|
+
Example:
|
|
11
|
+
>>> cerebro = bt.Cerebro()
|
|
12
|
+
>>> cerebro.addanalyzer(bt.analyzers.SQN, _name='sqn')
|
|
13
|
+
>>> results = cerebro.run()
|
|
14
|
+
>>> print(results[0].analyzers.sqn.get_analysis())
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import math
|
|
18
|
+
|
|
19
|
+
from ..analyzer import Analyzer
|
|
20
|
+
from ..mathsupport import average, standarddev
|
|
21
|
+
from ..utils import AutoOrderedDict
|
|
22
|
+
|
|
23
|
+
__all__ = ["SQN"]
|
|
24
|
+
|
|
25
|
+
_PNL_EPSILON = 1e-10
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# Get SQN indicator
|
|
29
|
+
class SQN(Analyzer):
|
|
30
|
+
"""SQN or SystemQualityNumber. Defined by Van K. Tharp to categorize trading
|
|
31
|
+
systems.
|
|
32
|
+
|
|
33
|
+
- 1.6 - 1.9 Below average
|
|
34
|
+
- 2.0 - 2.4 Average
|
|
35
|
+
- 2.5 - 2.9 Good
|
|
36
|
+
- 3.0 - 5.0 Excellent
|
|
37
|
+
- 5.1 - 6.9 Superb
|
|
38
|
+
- 7.0 - Holy Grail?
|
|
39
|
+
|
|
40
|
+
The formula:
|
|
41
|
+
|
|
42
|
+
- SquareRoot(NumberTrades) * Average(TradesProfit) / StdDev(TradesProfit)
|
|
43
|
+
|
|
44
|
+
The sqn value should be deemed reliable when the number of trades >= 30
|
|
45
|
+
|
|
46
|
+
Methods:
|
|
47
|
+
|
|
48
|
+
- get_analysis
|
|
49
|
+
|
|
50
|
+
Returns a dictionary with keys "sqn" and "trades" (number of
|
|
51
|
+
considered trades)
|
|
52
|
+
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
# System quality number
|
|
56
|
+
alias = ("SystemQualityNumber",)
|
|
57
|
+
|
|
58
|
+
# Create analysis
|
|
59
|
+
def create_analysis(self):
|
|
60
|
+
"""Replace default implementation to instantiate an AutoOrderedDict
|
|
61
|
+
rather than an OrderedDict"""
|
|
62
|
+
self.rets = AutoOrderedDict()
|
|
63
|
+
|
|
64
|
+
# Start, initialize pnl and count
|
|
65
|
+
def start(self):
|
|
66
|
+
"""Initialize the analyzer at the start of the backtest.
|
|
67
|
+
|
|
68
|
+
Initializes lists to store trade P&L values for SQN calculation.
|
|
69
|
+
"""
|
|
70
|
+
super().start()
|
|
71
|
+
self.pnl = []
|
|
72
|
+
self.count = 0
|
|
73
|
+
|
|
74
|
+
# Trade notification, if trade is closed, add profit/loss
|
|
75
|
+
def notify_trade(self, trade):
|
|
76
|
+
"""Collect P&L from closed trades.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
trade: The trade object that was closed.
|
|
80
|
+
"""
|
|
81
|
+
if trade.status == trade.Closed:
|
|
82
|
+
self.pnl.append(trade.pnlcomm)
|
|
83
|
+
self.count += 1
|
|
84
|
+
|
|
85
|
+
# Stop, calculate SQN indicator, if trade count > 0, SQN equals average trade profit * sqrt(trade count) / standard deviation of trade profit
|
|
86
|
+
def stop(self):
|
|
87
|
+
"""Calculate the System Quality Number when backtest ends.
|
|
88
|
+
|
|
89
|
+
SQN = sqrt(N) * average(P&L) / std(P&L)
|
|
90
|
+
|
|
91
|
+
The result is stored in self.rets.sqn along with the number of
|
|
92
|
+
trades in self.rets.trades.
|
|
93
|
+
"""
|
|
94
|
+
if self.count > 1:
|
|
95
|
+
try:
|
|
96
|
+
pnl_values = [0.0 if abs(value) <= _PNL_EPSILON else value for value in self.pnl]
|
|
97
|
+
pnl_av = average(pnl_values)
|
|
98
|
+
pnl_stddev = standarddev(pnl_values)
|
|
99
|
+
except (TypeError, ValueError, ZeroDivisionError):
|
|
100
|
+
sqn = None
|
|
101
|
+
else:
|
|
102
|
+
if not math.isfinite(pnl_av) or not math.isfinite(pnl_stddev) or pnl_stddev == 0.0:
|
|
103
|
+
sqn = None
|
|
104
|
+
else:
|
|
105
|
+
sqn = math.sqrt(len(self.pnl)) * pnl_av / pnl_stddev
|
|
106
|
+
if not math.isfinite(sqn):
|
|
107
|
+
sqn = None
|
|
108
|
+
else:
|
|
109
|
+
sqn = 0
|
|
110
|
+
# Set SQN value and trades value
|
|
111
|
+
self.rets.sqn = sqn
|
|
112
|
+
self.rets.trades = self.count
|