def test_backtest(): """ Ensures that the backtest function works on all the registered strategies, with their default parameter values """ sample = pd.read_csv(SAMPLE_CSV, parse_dates=["dt"]) # Simulate custom indicator sample["custom"] = np.random.random((sample.shape[0], )) * 100 for strategy in STRATEGY_MAPPING.keys(): if strategy == "sentiment": data = get_yahoo_data("TSLA", "2020-01-01", "2020-07-04") sentiments = get_bt_news_sentiment(keyword="tesla", page_nums=2) cerebro = backtest(strategy, data, sentiments=sentiments, senti=0.4, plot=False) errmsg = "Backtest encountered error for strategy '{}'!".format( strategy) assert cerebro is not None, errmsg else: cerebro = backtest(strategy, sample, plot=False) errmsg = "Backtest encountered error for strategy '{}'!".format( strategy) assert cerebro is not None, errmsg
def test_backtest(): """ Ensures that the backtest function works on all the registered strategies, with their default parameter values """ sample = pd.read_csv(SAMPLE_CSV, parse_dates=["dt"]) # Simulate custom indicator sample["custom"] = np.random.random((sample.shape[0], )) * 100 for strategy in STRATEGY_MAPPING.keys(): if strategy == "sentiment": data = get_yahoo_data("TSLA", "2020-01-01", "2020-07-04", dividends=True) # use cached data instead of scraping for tests purposes. # sentiments = get_bt_news_sentiment(keyword="tesla", page_nums=2) with open(SENTI_PKL, "rb") as handle: sentiments = pickle.load(handle) cerebro = backtest(strategy, data, sentiments=sentiments, senti=0.4, plot=False) errmsg = "Backtest encountered error for strategy '{}'!".format( strategy) assert cerebro is not None, errmsg data_disclosures = get_stock_data( "TSLA", "2020-01-01", "2020-09-30", dividends=True, # source="phisix" ) # sentiments_disclosures = get_disclosure_sentiment( # stock_code="JFC", # start_date="2020-07-01", # end_date="2020-09-30", # ) with open(DISCLOSURE_PKL, "rb") as handle_disclosures: sentiments_disclosures = pickle.load(handle_disclosures) cerebro_disclosures = backtest( strategy, data_disclosures, sentiments=sentiments_disclosures, senti=0.2, plot=False, ) errmsg_disclosures = "Backtest encountered error for strategy '{}'!".format( strategy) assert cerebro_disclosures is not None, errmsg_disclosures else: cerebro = backtest(strategy, sample, plot=False) errmsg = "Backtest encountered error for strategy '{}'!".format( strategy) assert cerebro is not None, errmsg
def test_multi_backtest(): """ Test multi-strategy """ sample = pd.read_csv(SAMPLE_CSV, parse_dates=["dt"]) cerebro = backtest("multi", sample, strats=SAMPLE_STRAT_DICT, plot=False) assert cerebro is not None, "Backtest encountered error for strategy 'multi'!"
def conditional_confirmation_strat(predf, condition='bionary', ma_var=5, plot_em=True): ''' takes in a condition [ a bot interested in longing ] and only buys when the price rises above a simple moving avg. returns a backtest results dataframe TAKES: 1. dataframe 2. condition column ( either > 0 OR ==True ) 3. ma_var - moving avg value 4. plot_em - to plot or not to plot.... ''' # BOT LONG IS THE CONDITION THAT HAS TO BE TRUE in for a buy to be triggered predf['bot_long'] = predf[ condition] > 0 #<---might have to change that to True # CREATE A MOVING AVG TO SERVE AS VALIDATION/CONFIRMATION predf['ma5'] = predf['Close'].rolling(ma_var).mean() # CONDITIONS predf['ma5_above'] = predf['Close'] > predf['ma5'] predf['bot_n_above'] = (predf['bot_long'] == True) & (predf['ma5_above'] == True) predf['confirmation'] = (predf['bot_n_above'] == True) & (predf['bot_n_above'].shift() == False) predf['validation'] = (predf['ma5_above'] == False) & (predf['ma5_above'].shift() == True) predf['trac'] = False predf['trigger'] = 0 # if conditions are met and we get confimation we get a tigger (predf[trigger])=1 for i in range(1, len(predf)): if predf['confirmation'][i] == True: predf['trac'][i] = True predf['trigger'][i] = 1 elif predf['validation'][i] == True: predf['trac'][i] = False predf['trigger'][i] = -1 else: predf['trac'][i] = predf['trac'][i - 1] # CREATE A SCALED VERSION FOR PLOTTING predf['trac_scale'] = predf['trac'].replace(True, 1).replace(1, predf.Close) #plot if plot_em: predf[['Close', 'trac_scale']].iplot(theme='solar', fill=True) results = backtest('ternary', predf, custom_column='trigger', init_cash=1000.00, plot=plot_em, verbose=False) return results
def test_backtest(): """ Ensures that the backtest function works on all the registered strategies, with their default parameter values """ sample = pd.read_csv(SAMPLE_CSV, parse_dates=["dt"]) for strategy in STRATEGY_MAPPING.keys(): cerebro = backtest(strategy, sample, plot=False) errmsg = "Backtest encountered error for strategy '{}'!".format( strategy) assert cerebro is not None, errmsg
def test_grid_backtest(): """ Test grid search """ sample = pd.read_csv(SAMPLE_CSV, parse_dates=["dt"]) cerebro = backtest( "smac", sample, fast_period=[20, 25], slow_period=[40, 50], plot=False ) assert ( cerebro is not None ), "Backtest encountered error doing grid search on SMAC!"
def test_backtest(): """ Ensures that the backtest function works on all the registered strategies, with their default parameter values """ sample = pd.read_csv(SAMPLE_CSV, parse_dates=["dt"]) for strategy in STRATEGY_MAPPING.keys(): if strategy == "sentiment": data = get_yahoo_data("TSLA", "2020-01-01", "2020-06-10") cerebro = backtest( strategy, data, keyword="tesla", page_nums=2, senti=0.4 ) errmsg = "Backtest encountered error for strategy '{}'!".format( strategy ) assert cerebro is not None, errmsg else: cerebro = backtest(strategy, sample, plot=False) errmsg = "Backtest encountered error for strategy '{}'!".format( strategy ) assert cerebro is not None, errmsg
def buy_delta(df, THRESH, SELL): df = delta_maker(df, THRESH) BUY = 'delta_ab_thresh' df['buy'] = (df[BUY].shift() == False) & (df[BUY] == True) df['sell'] = (df[SELL].shift() == False) & (df[SELL] == True) df = compile_signals(df) result = backtest(df, plot_capital=True, strat_name='delta_experiments') result['delta_thresh'] = THRESH return result
def test_grid_backtest(): """ Test grid search """ sample = pd.read_csv(SAMPLE_CSV, parse_dates=["dt"]) cerebro = backtest( "smac", sample, fast_period=range(15, 30, 3), slow_period=range(40, 55, 3), plot=False, ) assert cerebro is not None, "Backtest encountered error doing grid search on SMAC!"
def smac_backtest(df, var1, var2, plot=False): ''' var1 = fast var2 = slow ''' result = backtest('smac', df, fast_period=var1, slow_period=var2, init_cash=1000, plot=plot) strat_name = 'smac' result['strat_name'] = 'smac' return result, strat_name
def rsi_backtest(df, var1, var2, plot=False): ''' var1 - rsi_lower var2 - rsi_upper ''' result = backtest('rsi', df, rsi_lower=var1, rsi_upper=var2, init_cash=1000, plot=plot) strat_name = 'rsi-14:' result['strat_name'] = strat_name return result, strat_name
def macd_backtest(df, var1, var2, plot=False): ''' var1 = fast_period - should be smaller than slow_upper var2 = slow_period - shoudl be larget than fast_upper ''' result = backtest( 'macd', df, fast_period=var1, slow_period=var2, signal_period=14, #allowance = 6, init_cash=1000, plot=plot) result['allowance'] = 6 result['signal_period'] = 14 strat_name = 'macd:' result['strat_name'] = strat_name return result, strat_name
def sma_up_validation(df, sma_variable, long_sma, strat_name, look_back, rdf, plot_capital=False): ''' takes: 1.df 2.sma - float, when price is above this sma it will by ... 3.long_sma - float, will only buy if this is pointing up 4. results dataframe to append results to returns: final_acnt value for grid plot ''' df = df[['close', 'low', 'open', 'high']] df['longer_sma'] = df['close'].rolling(long_sma).mean().shift() df['moving_avg'] = df['low'].rolling(sma_variable).mean().shift() df['price_abv_ma'] = df['close'] > df['moving_avg'] df['buy_sma'] = (df['price_abv_ma'] == True) & (df['price_abv_ma'].shift() == False) df['sell'] = (df['price_abv_ma'] == False) & (df['price_abv_ma'].shift() == True) df['longer_up'] = (df['longer_sma'] > df['longer_sma'].shift(look_back)) df['buy'] = (df['buy_sma'] == True) & (df['longer_up'] == True) #..................................................................................................... df = compile_signals(df) result = backtest(df, strat_name='SMA-Price-CROSS', plot_capital=plot_capital) #print(result) result['validation'] = sma_variable result['sma_has_to_be_up'] = long_sma rdf = rdf.append(result) result['look_back'] = look_back return result['final_acnt value'][0], result
def backtest_data_gdsr(df): ''' Summary: ---------- Open json trading strategy file, test strategies through fastquant backtest Params: ---------- df : dataframe with financial data Outputs: ---------- none ''' json_file_path = os.path.join(sys.path[0], 'bt_strats_params.json') with open(json_file_path, encoding='utf-8', errors='ignore') as json_data: strat_dict = json.load(json_data, strict=False) for strat in strat_dict['strats']: bt = backtest("multi", df, strats=strat, plot=True) print(bt)
def atr_back_test(m, df, to_plot=False, up_multiple=2, dn_multiple=2, plot_trac=False): ''' this function does the backtest things m is for model ''' df['atr'] = pta.atr(df.High, df.Low, df.Close) bdf = df[[m, 'atr', 'High', 'Low', 'Close']].dropna(axis=0) #sns.heatmap(bdf.isnull()) bdf['atr_up'] = (bdf['Close'] + bdf['atr'] * up_multiple) bdf['atr_down'] = (bdf['Close'] - bdf['atr'] * dn_multiple) ##### later create a function that makes variations of ups and downs #### to_be an ATR -LOOP # STRAT FUNCTION ### starts here... '''llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll''' '''inputs''' buy = m #'Tree165473' t_up = 'atr_up' t_dn = 'atr_down' #SO this needs to go into a function and will be part of the backtest loop for each model # atr_targs and stop will be inputs so i can iterate through #if bdf.index.name == 'date': # bdf = bdf.reset_index() bdf['trac'] = False bdf['targ'] = bdf[t_up] bdf['stop'] = bdf[t_dn] for i in range(1, len(bdf)): if (bdf[buy][i] == True) & (bdf['trac'][i - 1] == False): bdf['trac'][i] = True bdf['targ'][i] = bdf[t_up][i] bdf['stop'][i] = bdf[t_dn][i] elif (bdf['trac'][i - 1] == True) & ( (bdf['Low'][i] < bdf['stop'][i - 1]) | (bdf['High'][i] > bdf['targ'][i - 1])): bdf['trac'][i] = False else: bdf['trac'][i] = bdf['trac'][i - 1] bdf['targ'][i] = bdf['targ'][i - 1] bdf['stop'][i] = bdf['stop'][i - 1] #hl(bdf) #print(s) #tit = (s + '_'+m) if to_plot == True: #sola(bdf[['stop','Close','targ']])#,title=tit) bdf[['stop', 'Close', 'targ']].iplot(theme='solar', fill=True) ## todo- replace 'strat' with a varable bdf['strat'] = 0 for i in range(1, len(bdf)): if (bdf['trac'][i - 1] == False) & (bdf['trac'][i] == True): bdf['strat'][i] = 1 elif (bdf['trac'][i - 1] == True) & (bdf['trac'][i] == False): bdf['strat'][i] = -1 #hl(bdf) #bdf =bdf.set_index('date')#.drop(['level_0','index'],axis=1) bdf #%matplotlib results, history = backtest('ternary', bdf, custom_column='strat', init_cash=1000, plot=plot_trac, verbose=False, return_history=True) #results['model'] = buy #results['target']= target #results['sheet'] = s results['strat_type'] = 'atr_smacks' results['up_multiple'] = up_multiple results['dn_multiple'] = dn_multiple #results = results.set_index('custom_column') #results['buy'] = buy #se if plot_trac: bdf['trac'] = bdf['trac'].replace(True, 1).replace(1, bdf.Close) bdf[['Close', 'High', 'trac']].iplot(theme='solar', fill=True) return results
from fastquant import backtest, get_stock_data df = get_stock_data("AAAA", "2018-01-01", "2021-04-01") res, plot = backtest('emac', df, init_cash=2000, fast_period=10, slow_period=30, return_plot=True) #plot.savefig('AAAA_emac.png')
from fastquant import backtest, get_stock_data df = get_stock_data("AAAA", "2018-03-01", "2021-04-01") ############smac###################### res, plot = backtest('smac', df, init_cash=2000, sell_prop=1, buy_prop=1, fast_period=10, slow_period=30, return_plot=True) #plot.savefig('AAAA_smac.png')
def back_test_things(m, to_plot=False, up_multiple=2, dn_multiple=2): ''' this function does the backtest things m is for model ''' df['atr'] = pta.atr(df.High, df.Low, df.Close) bdf = df[[m, 'atr', 'High', 'Low', 'Close']].dropna(axis=0) #sns.heatmap(bdf.isnull()) bdf['atr_up'] = (bdf['Close'] + bdf['atr'] * up_multiple) bdf['atr_down'] = (bdf['Close'] - bdf['atr'] * dn_multiple) ##### later create a function that makes variations of ups and downs #### to_be an ATR -LOOP # STRAT FUNCTION ### starts here... '''llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll''' '''inputs''' buy = m #'Tree165473' t_up = 'atr_up' t_dn = 'atr_down' #SO this needs to go into a function and will be part of the backtest loop for each model # atr_targs and stop will be inputs so i can iterate through if bdf.index.name == 'date': bdf = bdf.reset_index() bdf['trac'] = False bdf['targ'] = bdf[t_up] bdf['stop'] = bdf[t_dn] for i in range(1, len(bdf)): if (bdf[buy][i] == True) & (bdf['trac'][i - 1] == False): bdf['trac'][i] = True bdf['targ'][i] = bdf[t_up][i] bdf['stop'][i] = bdf[t_dn][i] elif (bdf['trac'][i - 1] == True) & ( (bdf['Low'][i] < bdf['stop'][i - 1]) | (bdf['High'][i] > bdf['targ'][i - 1])): bdf['trac'][i] = False else: bdf['trac'][i] = bdf['trac'][i - 1] bdf['targ'][i] = bdf['targ'][i - 1] bdf['stop'][i] = bdf['stop'][i - 1] #hl(bdf) print(s) tit = (s + '_' + m) #if to_plot==True: #sola(bdf[['stop','Close','targ']],title=tit) ## todo- replace 'strat' with a varable bdf['strat'] = 0 for i in range(1, len(bdf)): if (bdf['trac'][i - 1] == False) & (bdf['trac'][i] == True): bdf['strat'][i] = 1 elif (bdf['trac'][i - 1] == True) & (bdf['trac'][i] == False): bdf['strat'][i] = -1 #hl(bdf) bdf = bdf.set_index('date') #.drop(['level_0','index'],axis=1) bdf #%matplotlib results, history = backtest('ternary', bdf, custom_column='strat', init_cash=1000, plot=to_plot, verbose=False, return_history=True) results['model'] = buy results['target'] = target results['sheet'] = s results['up_multiple'] = up_multiple results['dn_multiple'] = dn_multiple #results = results.set_index('custom_column') #results['buy'] = buy #se results.T ### so now i need to rename the thing after the strat and atr paramaters #### ##### this is ready to become a save_function... but btpath = 'backtest_data/' if not os.path.exists(btpath): os.mkdir(btpath) fname = 'results.csv' if not os.path.exists(btpath + fname): print('dosnt exitst') rdf = results rdf.to_csv(btpath + fname) print('results.csv created') else: rdf = pd.read_csv(btpath + fname).drop('Unnamed: 0', axis=1) print('already exists') rdf = rdf.append(results) print('apending') rdf.to_csv(btpath + fname) print('results.csv UPDATED!')
def get_strategy(symbol: str, model: str, initial_cash: int, commission_percentage: float, short_sell: bool, margin_percentage: float, investment_period: int): try: df = get_stock_data(symbol, investment_period) df.rename( columns={ "open_price": "Open", "high_price": "High", "low_price": "Low", "close_price": "Close", "volume": "Volume", }, inplace=True, ) next_n_trading_days = get_next_n_trading_days(investment_period) preds = get_predictions(symbol, next_n_trading_days.min(), next_n_trading_days.max(), model).to_frame() df1 = preds.combine_first(df[["Close"]]) kwargs = { "data": df1[-investment_period:].fillna(method="ffill"), "init_cash": initial_cash, "commission": commission_percentage, "allow_short": short_sell, "short_max": margin_percentage, "return_history": True, "verbose": 0, "plot": False } strategies = { "smac": { "fast_period": 15, "slow_period": 40, }, "emac": { "fast_period": 15, "slow_period": 40, }, "buynhold": {}, "bbands": { "period": 30, "devfactor": 1, }, "rsi": { "rsi_period": 7, "rsi_upper": 70, "rsi_lower": 35, }, "macd": { "fast_period": 15, "slow_period": 40, "signal_period": 20, "sma_period": 30, "dir_period": 10, }, } strategies["multi"] = { "strats": {strat: strategies[strat] for strat in ("rsi", "smac")} } max_pnl = 0 max_strategy = None max_res = None max_trades = None for strategy, s_kwargs in strategies.items(): try: res, trades = backtest(strategy, **s_kwargs, **kwargs) net_pnl = res.pnl[0] if max_pnl < net_pnl: max_pnl = net_pnl max_res = res max_trades = trades max_strategy = strategy except Exception: pass if max_strategy: final_trades = [{ "type": order['type'], "size": abs(order['size']), "price": order['price'], "date": order['dt'].to_pydatetime().date(), "value": order.value, "commission": order.commission, "pnl": order.pnl } for _, order in max_trades["orders"].iterrows()] final_value = max_res.final_value[0] final_capital = final_value - max_pnl return { "name": max_strategy, "pnl": max_pnl, "value": final_value, "capital": final_capital, "pnl_pct": (final_value - final_capital) / final_capital * 100, "trades": final_trades } except Exception as e: logger.exception(e) return
from fastquant import backtest, get_stock_data df = get_stock_data("AAAA", "2018-01-01", "2021-04-01") res,plot = backtest('macd', df, init_cash=2000, fast_period=12, slow_period=26, signal_period=9, sma_period=30, dir_period=10, return_plot=True) #plot.savefig('AAAA_macd.png')
from fastquant import get_stock_data, backtest from datetime import date today = date.today() df = get_stock_data("WFG.TO", "2015-09-01", today) backtest('smac', df, fast_period=25, slow_period=52) # res = backtest("smac", df, fast_period=range(10, 30, 3), slow_period=range(40, 55, 3), verbose=False) # print(res[['fast_period', 'slow_period', 'final_value']].head()) #
# "custom_column": "custom2" # }, } strategies["multi"] = { "strats": {strat: strategies[strat] for strat in ("rsi", "smac")} } max_pnl = 0 max_strategy = None max_res = None for strategy, s_kwargs in strategies.items(): try: res = backtest(strategy, **s_kwargs, **kwargs) net_pnl = res[0].pnl[0] print(strategy) print(f"Net PnL: {net_pnl}") print() if max_pnl < net_pnl: max_pnl = net_pnl max_res = res max_strategy = strategy except Exception: pass print()
from fastquant import backtest, get_stock_data jfc = get_stock_data("JFC", "2018-01-01", "2019-01-01") backtest('smac', jfc, fast_period=15, slow_period=40)
def back_test(i): subset = stocks_data[stocks_data["Symbol"]==i] #[HorizonPeriod:] #converts date to datetime stock = StockDataFrame.retype(subset[["Date","Open", "High", "Low", "Close", "Adj Close", "Volume"]]) #EVWMA Short_EVWMA = pd.DataFrame(TA.EVWMA(subset,9)) Signal_EVWMA = pd.DataFrame(TA.EVWMA(subset,12)) Long_EVWMA = pd.DataFrame(TA.EVWMA(subset,26)) ATR = pd.DataFrame(TA.ATR(subset)) Short_EVWMA.columns = ['EVWMA_9'] Signal_EVWMA.columns = ['EVWMA_12'] Long_EVWMA.columns = ['EVWMA_26'] ATR.columns = ['ATR'] MACD_EVWMA = pd.DataFrame(Long_EVWMA['EVWMA_26'] - Short_EVWMA['EVWMA_9']) MACD_EVWMA.columns = ['Signal'] #Adj Close ts = subset[["Date","Adj Close"]] ts.columns = ['ds', 'y'] #print(ts) m = Prophet(daily_seasonality=True,yearly_seasonality=True) m.add_seasonality(name='monthly', period=30.5, fourier_order=5) m.add_seasonality(name='quarterly', period=91.25, fourier_order=7) m.fit(ts[HorizonPeriod:]) #forecast = m.make_future_dataframe(periods=0, freq='D') forecast = pd.DataFrame(idx3) forecast.columns = ['ds'] #forecast2 = pd.DataFrame(df.index)[HorizonPeriodho+50:] #forecast2.columns = ['ds'] # Predict and plot pred = m.predict(forecast) #pred2 = m.predict(forecast2) dfpre = stock idx1 = dfpre.index #create entry for next trading day (i.e. idx3) merged = idx1.union(idx3) newdf = dfpre.reindex(merged) #A. fbprophet return expected_1day_return = pred.set_index("ds").yhat.pct_change().shift(-1).multiply(100) newdf["custom"] = expected_1day_return.multiply(-1) #B. no fbprophet #newdf['custom'] = ts.set_index('ds') #fbprophet #newdf["custom"] = pred.set_index('ds')['yhat'] #rmse #delta = len(pred.set_index('ds')['yhat'][HorizonPeriod:])-len(df['close'].dropna()) rmse = mean_squared_error(newdf['close'].dropna()[HoldoutPeriod:(HorizonPeriod-1)], pred.set_index('ds')['yhat'][HoldoutPeriod:(HorizonPeriod-1)], squared=True) mape = MAPE(newdf['close'].dropna()[HoldoutPeriod:(HorizonPeriod-1)], pred.set_index('ds')['yhat'][HoldoutPeriod:(HorizonPeriod-1)]) #df = dfpre[(dfpre['Date']> "2018-01-01") & (df['Date']<= end)] df = newdf[HorizonPeriod:] #df["custom"] = (((pred.set_index('ds')['yhat']-ts.set_index('ds')['y'])/ts.set_index('ds')['y']).multiply(-1))[HorizonPeriod:] with contextlib.redirect_stdout(None): b = backtest("multi", df.dropna(), strats=strats_opt, return_history=True, buy_prop=0.10, sell_prop=1,commission=0.01, init_cash=1000) r = {'backtest':b, 'score1':rmse, 'score2':mape, 'name':i, 'forecast':pred} return (r)
#print(type(training_data)) #print(training_data.info()) #print(training_data.head()) model, _ = train_predictor.train(model, training_data, roondiwala.label_column_index) preds, actual = train_predictor.predict(model, back_test_data, roondiwala.label_column_index) preds = pd.DataFrame(data=np.array(preds), columns=['yhat']) expected_1day_return = preds['yhat'].pct_change().shift(-1).multiply(100) back_test_data['custom'] = expected_1day_return.multiply(-1).values print('testing...') res,history = backtest("custom", back_test_data.dropna(), upper_limit=3, lower_limit=-2, buy_prop=1, sell_prop=1, return_history=True, execution_type='close', plot=False, verbose=0) results[f'{ticker}, {start}-{end}'] = percentage_gain(float(res['init_cash']), float(res['final_value'])) dump = json.dumps(results) output_file = open('roondiwala_fastquant_results.json', 'w') output_file.write(dump) output_file.close()
from fastquant import backtest, get_stock_data df = get_stock_data("AAAA", "2018-01-01", "2021-04-01") res, plot = backtest('bbands', df, init_cash=2000, period=20, devfactor=2.0, return_plot=True) #plot.savefig('AAAA_bbands.png')