vectorbt icon indicating copy to clipboard operation
vectorbt copied to clipboard

the MA cross over function not picking all crossovers

Open rramin136 opened this issue 3 years ago • 12 comments

Hi I am new to vbt and github! Hope I am posting in the right spot. I am cross-checking the results of a simple MA crossover strategy in vbt vs Bloomberg's backtesting platform ( via the terminal ). I have realized that the crossover function in vbt does not always pick up the crossovers that happen in a short period of time. for example, if there are 4 crossovers in say a 10 day period, vbt will miss a few of them. The codes I am using is here (TData is my original dataframe that contains the stock prices)

import vectorbt as vbt vbt.settings.portfolio['init_cash'] = 100000 vbt.settings.portfolio['fees'] = 0.0
vbt.settings.portfolio['slippage'] = 0.00
fast_window = 1 slow_window = 200 fast_ma = vbt.MA.run(TData, fast_window) slow_ma = vbt.MA.run(TData, slow_window) dmac_entries = fast_ma.ma_crossed_above(slow_ma) dmac_exits = fast_ma.ma_crossed_below(slow_ma) dmac_pf = vbt.Portfolio.from_signals(TData, dmac_entries, dmac_exits) print(dmac_pf.stats())

rramin136 avatar Jan 27 '22 03:01 rramin136

@rramin136 you need to provide a reproducible example with data, otherwise I see no issues with the crossovers. The only time when a crossover may not be generated is when there are NaNs.

polakowo avatar Jan 27 '22 09:01 polakowo

@polakowo Do you have access to Bloomberg?

rramin136 avatar Jan 27 '22 11:01 rramin136

@rramin136 no. The reason why some of your crossovers are not showed is because of the warmup period (moving average with a period of 100 days cannot generate any crossovers in the period of the first 100 days since not all data is available, Bloomberg on the other hand has all data).

polakowo avatar Jan 27 '22 11:01 polakowo

@polakowo , I actually adjusted Bloomberg so that the time stamp of first trades on both Bloomberg and VBT is the same. They then go hand in hand until vbt misses a couple of trades etc.. interestingly enough if I increase the period of the short ma from 1 to say 50, the discrepancies disappear

rramin136 avatar Jan 27 '22 11:01 rramin136

@rramin136 it's unusual to see a rolling window of 1, but it should generate the same values as the price. If you are able to pull the data and make it available for me to download, I could investigate this.

polakowo avatar Jan 27 '22 11:01 polakowo

@polakowo pushing the model parameters to the extremes(high or low) has helped me a lot in detecting malfunctions etc. But as for the results, would backtested results from Bloomberg and vbt do?

rramin136 avatar Jan 27 '22 11:01 rramin136

@rramin136 can you plot both moving averages and mark the crossovers which haven't been generated?

polakowo avatar Jan 28 '22 15:01 polakowo

@polakowo I came across the same problem when I ran my backtest. You may use the following dual SMA cross signals to duplicate the problem.

====== test code start ================== import pandas as pd import vectorbt as vbt from datetime import datetime import pytz

symbol = 'SPY' s_date = datetime(2020, 1 , 1, tzinfo=pytz.utc) e_date = datetime(2023, 1, 1, tzinfo=pytz.utc)

signal_close = vbt.YFData.download(symbol, start=s_date, end=e_date).get('Close') # vbt format, pickleable

''' set ma parameters ''' fast_period = 4
slow_period = 6
''' if slow_period - fast_period <= 2, there will be missing crossed_over/below generated by VBT e.g. fast_period = 4 and slow_period = 6 will have problem but fast_period = 4 and slow_period = 10 will NOT have problem '''

''' use rolling mean to generate long/short signals ''' fast_sma = signal_close.rolling(fast_period).mean() slow_sma = signal_close.rolling(slow_period).mean() long = (fast_sma > slow_sma) & (fast_sma.shift(1) < slow_sma.shift(1))
short = (fast_sma < slow_sma) & (fast_sma.shift(1) > slow_sma.shift(1))

''' use VBT.crossed_above/below to generate long/short signals ''' vbt_fast_ma = vbt.MA.run(signal_close, window=fast_period, short_name='ma') vbt_slow_ma = vbt.MA.run(signal_close, window=slow_period, short_name='ma') vbt_long = vbt_fast_ma.ma_crossed_above(vbt_slow_ma) vbt_short = vbt_fast_ma.ma_crossed_below(vbt_slow_ma)

''' compare signals ''' long_compare = (long == vbt_long).astype(int) short_compare = (short == vbt_short).astype(int)

''' combine result and export for compare ''' df_temp = pd.concat([signal_close, fast_sma, slow_sma, long.astype(int), short.astype(int), vbt_fast_ma.ma, vbt_slow_ma.ma, vbt_long.astype(int), vbt_short.astype(int), long_compare, short_compare], axis=1) df_temp.columns=[symbol, 'fast_ma', 'slow_ma', 'long', 'short', 'vbt_fast_ma', 'vbt_slow_ma', 'vbt_long', 'vbt_short', 'long_compare', 'short_compare'] df_temp.to_csv('signals.csv')

=========== test code end ===============

In the "signals.csv" file, if long_compare = 0 or short_compare=0, it means the VBT MA crossed_above/below function missing this signal point. You may find the missing cross-overs in the following timestamp with fast_period = 4 and slow_period = 6.

2020-04-22 00:00:00+00:00 2020-04-23 00:00:00+00:00 2020-10-27 00:00:00+00:00 2021-01-06 00:00:00+00:00 2021-03-05 00:00:00+00:00 2021-08-04 00:00:00+00:00 2021-08-05 00:00:00+00:00

I find that if (slow_period - fast_period) <= 2, there will be missing crossed_above/below generated by VBT

e.g. fast_period = 4 and slow_period = 5 or 6 will have problem but fast_period = 4 and slow_period = 10 will NOT have problem

Please help to fix this. Many thanks.

eelsk94 avatar Feb 04 '22 18:02 eelsk94

@eelsk94 I'll take a look at it, will be back soon.

polakowo avatar Feb 04 '22 18:02 polakowo

@eelsk94 can reproduce, crossovers are not generated properly when they are at two consecutive ticks. Fix is underway.

polakowo avatar Feb 04 '22 19:02 polakowo

Fixed in 0.23.2.

polakowo avatar Feb 04 '22 19:02 polakowo

@eelsk94 can reproduce, crossovers are not generated properly when they are at two consecutive ticks. Fix is underway.

hi, do you know if ta (technical analysis library) has a similar ema_crossed_above or below like vbt and pandas_ta does w ma_crossed_above or below ? Side question and root question, i could not figure out the syntax for vtb comb for EMA via pandas_ta (withyahoo btc daily feed) so maybe that is the REAL question. then i could just use the cross helper functon in pandas_ta or should i add a ema to vbt with a vbt MA like class for EMA?

based on the example in your docs i tried fast_ma, slow_ma = vbt.MA.run_combs(price, window=windows, r=2, short_names=['fast', 'slow']) entries = fast_ma.ma_crossed_above(slow_ma) exits = fast_ma.ma_crossed_below(slow_ma) worked great. got a nice heatmap later...but...i tried to do the same w EMA, using pandas_ta, no luck :/ bc i dont understand the syntax needed i suppose.

fast_ema, slow_ema = vbt.pandas_ta('EMA').run_combs(price, window=windows, r=2, short_names=['fast', 'slow']) but it didnt work . any help appreciated. thanks in advance. id prefer to use pandas_ta if i can get the syntax of that ema + comb line working. :D

cryptoliciousdev avatar Jul 25 '22 05:07 cryptoliciousdev