vectorbt
vectorbt copied to clipboard
the MA cross over function not picking all crossovers
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 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 Do you have access to Bloomberg?
@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 , 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 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 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 can you plot both moving averages and mark the crossovers which haven't been generated?
@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 I'll take a look at it, will be back soon.
@eelsk94 can reproduce, crossovers are not generated properly when they are at two consecutive ticks. Fix is underway.
Fixed in 0.23.2.
@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