def test_turnover(): dts = pd.date_range('2010-01-01', periods=5) data = pd.DataFrame(index=dts, columns=['a', 'b'], data=100) data['a'][dts[1]] = 105 data['b'][dts[1]] = 95 data['a'][dts[2]] = 110 data['b'][dts[2]] = 90 data['a'][dts[3]] = 115 data['b'][dts[3]] = 85 s = bt.Strategy('s', [bt.algos.SelectAll(), bt.algos.WeighEqually(), bt.algos.Rebalance()]) t = bt.Backtest(s, data, commissions=lambda x, y: 0, progress_bar=False) res = bt.run(t) t = res.backtests['s'] # these numbers were (tediously) calculated in excel assert t.turnover[dts[0]] == 0. / 1000000 assert t.turnover[dts[1]] == 24985. / 1000000 assert t.turnover[dts[2]] == 24970. / 997490 assert t.turnover[dts[3]] == 25160. / 992455 assert t.turnover[dts[4]] == 76100. / 1015285
def beta(data, name='Strategy'): s = bt.Strategy(name, [bt.algos.RunOnce(), bt.algos.SelectAll(), bt.algos.WeighEqually(), bt.algos.Rebalance()]) bt_engine = bt.Backtest(s, data) res = bt.run(bt_engine) return res
def test_securitybase_allocate_commisions(): date_span = pd.DatetimeIndex(start='10/1/2017', end='10/11/2017', freq='B') numper = len(date_span.values) comms = 0.01 data = [[10, 15, 20, 25, 30, 35, 40, 45], [10, 10, 10, 10, 20, 20, 20, 20], [20, 20, 20, 30, 30, 30, 40, 40], [20, 10, 20, 10, 20, 10, 20, 10]] data = [[row[i] for row in data] for i in range(len(data[0]))] # Transpose price = pd.DataFrame(data=data, index=date_span) price.columns = ['a', 'b', 'c', 'd'] # price = price[['a', 'b']] sig1 = pd.DataFrame(price['a'] >= price['b'] + 10, columns=['a']) sig2 = pd.DataFrame(price['a'] < price['b'] + 10, columns=['b']) signal = sig1.join(sig2) signal1 = price.diff(1) > 0 signal2 = price.diff(1) < 0 tw = price.copy() tw.set_value(tw.index, tw.columns, 0) # Initialize Set everything to 0 tw[signal1] = -1.0 tw[signal2] = 1.0 s1 = bt.Strategy( 'long_short', [bt.algos.WeighTarget(tw), bt.algos.RunDaily(), bt.algos.Rebalance()]) ####now we create the Backtest , commissions=(lambda q, p: abs(p * q) * comms) t = bt.Backtest(s1, price, initial_capital=1000000, commissions=(lambda q, p: abs(p * q) * comms)) ####and let's run it! res = bt.run(t)
def benchmark_2(): x = np.random.randn(10000, 1000) * 0.01 idx = pd.date_range('1990-01-01', freq='B', periods=x.shape[0]) data = np.exp(pd.DataFrame(x, index=idx).cumsum()) bidoffer = data * 0.01 coupons = data * 0. s = bt.FixedIncomeStrategy( 's', algos=[ bt.algos.RunMonthly(), bt.algos.SelectRandomly(len(data.columns) / 2), bt.algos.WeighRandomly(), bt.algos.Rebalance() ], children=[bt.CouponPayingSecurity(c) for c in data]) t = bt.Backtest(s, data, additional_data={ 'bidoffer': bidoffer, 'coupons': coupons }) return bt.run(t)
def benchmark_3(): # Similar to benchmark_1, but with trading in only a small subset of assets # However, because the "multipier" is used, we can't just pass the string # names to the constructor, and so the solution is to use the lazy_add flag. # Changing lazy_add to False demonstrates the performance gain. # i.e. on Win32, it went from 4.3s with the flag to 10.9s without. x = np.random.randn(10000, 1000) * 0.01 idx = pd.date_range('1990-01-01', freq='B', periods=x.shape[0]) data = np.exp(pd.DataFrame(x, index=idx).cumsum()) children = [ bt.Security(name=i, multiplier=10, lazy_add=False) for i in range(1000) ] s = bt.Strategy('s', [ bt.algos.RunMonthly(), bt.algos.SelectThese([0, 1]), bt.algos.WeighRandomly(), bt.algos.Rebalance() ], children=children) t = bt.Backtest(s, data) return bt.run(t)
def spread_val_backtest(data_df_score, return_series_df): signal_bool = spread_wghts(data_df_score) signal_bool.columns = [return_series_df.columns.values[0]] trsy_bool = trsy_bool_position(signal_bool) trsy_bool.columns = [return_series_df.columns.values[1]] combined_positions = pd.concat([signal_bool,trsy_bool], axis=1) combined_positions = combined_positions.shift(1) start_date = np.min(combined_positions.index.values) end_date = np.max(combined_positions.index.values) return_series_df = return_series_df.ix[start_date:end_date] s1 = bt.Strategy('Spread Valuation', [bt.algos.WeighTarget(combined_positions), bt.algos.Rebalance()]) strategy = bt.Backtest(s1, return_series_df) res = bt.run(strategy) res.plot() res.plot_weights() res.display() return res pass
def main(): data = pd.read_excel('us_hy_credit.xlsx', index_col=0) data_df = data.copy() data_df[['HY Tot Index','US Trs Tot Index','IG Tot Index','Cash Tot Index']] = data_df[['US HY Return','US Int. Trsy Return','US IG Return','Cash Return']].add(1).cumprod() hy_spread = data_df['US HY Spread'].to_frame() hy_monthly_returns = data_df[['US HY Return','US Int. Trsy Return']] #hy_val_score = spread_val_score(hy_spread) #hy_val_res = spread_val_backtest(hy_val_score,hy_return_series) hy_mm_test, hy_mm_wghts = credit_momentum_test(hy_monthly_returns) hy_eq_mm_test, hy_eq_mm_wghts = equity_mm_test(data_df[['US HY Return','Cash Return','S&P 500 Return','US Int. Trsy Return']]) hy_eq_vol_test, hy_eq_vol_wghts = equity_vol_test(data_df[['US HY Return','US Int. Trsy Return','Equity Volatility']]) hy_sp_test, hy_sp_wghts = spread_holding_test(data_df[['US HY Return','US Int. Trsy Return','US HY Spread']]) #return_test, return_wghts = return_reversal(data_df[['US HY Return','US Int. Trsy Return']]) behavioral_bucket = 0.75 #behavioral hy_mm_wghts = hy_mm_wghts * behavioral_bucket * 1/3 hy_eq_mm_wghts = hy_eq_mm_wghts * behavioral_bucket * 1/3 hy_eq_vol_wghts = hy_eq_vol_wghts * behavioral_bucket * 1/3 #premia premia_ratio = 0.25 hy_sp_wghts = hy_sp_wghts * premia_ratio combined_wghts = hy_mm_wghts + hy_eq_mm_wghts + hy_eq_vol_wghts + hy_sp_wghts combined_wghts = pd.rolling_mean(combined_wghts, window=2) max_value = (max(combined_wghts.max())) combined_wghts = combined_wghts / max_value weighted_returns = combined_wghts * data_df[['US HY Return','US Int. Trsy Return']] combined_portfolio = weighted_returns.sum(axis=1).to_frame() combined_portfolio = combined_portfolio.add(1).cumprod() combined_test = long_only_ew(combined_portfolio, name='Combined') temp_df = pd.DataFrame(np.where(combined_wghts>0,True,False),index=combined_wghts.index,columns=['High Yield Weight','Treasury Weight']) values_temp = temp_df['High Yield Weight'].values x = np.diff(np.where(np.concatenate(([values_temp[0]], values_temp[:-1] != values_temp[1:], [True])))[0])[::2] print(x, np.mean(x),np.median(x)) res = bt.run(combined_test,hy_mm_test,hy_eq_mm_test,hy_eq_vol_test,hy_sp_test) res.plot() res.display() correlation_df = pd.DataFrame(res.prices) correlation_df = pd.DataFrame.pct_change(correlation_df,periods=1) correlation_df.dropna(inplace=True) print(correlation_df.corr())
import pylab as plt os.chdir('/home/olivier/Code/Python/bttest/') ts_data = pd.read_csv('alltimesseries.csv') ts_data['Date'] = [dt.datetime.strptime(x,'%Y-%m-%d') for x in ts_data['Date']] ts_data.set_index('Date', inplace = True) s = bt.Strategy('s1', [bt.algos.RunMonthly(), bt.algos.SelectAll(), bt.algos.WeighEqually(), bt.algos.Rebalance()]) test = bt.Backtest(s, ts_data['CL1']) res = bt.run(test) res.plot() plt.show() s2 = bt.Strategy('s2', [bt.algos.RunWeekly(), bt.algos.SelectAll(), bt.algos.WeighInvVol(), bt.algos.Rebalance()]) # now let's test it with the same data set. We will also compare it with our first backtest. test2 = bt.Backtest(s2, ts_data) res2 = bt.run(test, test2)
bt_strategy = bt.Strategy(name, [ bt.algos.SelectWhere(price_data > sma), bt.algos.WeighEqually(), bt.algos.Rebalance() ]) # Return the backtest return bt.Backtest(bt_strategy, price_data) # Create signal strategy backtest sma10 = signal_strategy('tsla', period=10, name='SMA10') sma30 = signal_strategy('tsla', period=30, name='SMA30') sma50 = signal_strategy('tsla', period=50, name='SMA50') # Run all backtests and plot the resutls bt_results = bt.run(sma10, sma30, sma50) bt_results.plot(title='Strategy optimization') plt.show() # BENCHMARKING def buy_and_hold(ticker, name, start='2020-2-1', end='2020-11-1'): # Get the data price_data = bt.get(ticker, start=start, end=end) # Define the benchmark strategy bt_strategy = bt.Strategy(name, [ bt.algos.RunOnce(), bt.algos.SelectAll(), bt.algos.WeighEqually(), bt.algos.Rebalance() ])
import bt import talib # Construct the signal signal[stock_rsi > 70] = -1 signal[stock_rsi < 30] = 1 signal[(stock_rsi <= 70) & (stock_rsi >= 30)] = 0 # Merge the data combined_df = bt.merge(signal, price_data) combined_df.columns = ['signal', 'Price'] combined_df.plot(secondary_y=['signal']) plt.show() # Define the strategy bt_strategy = bt.Strategy('RSI_MeanReversion', [bt.algos.WeighTarget(signal), bt.algos.Rebalance()]) # Create the backtest and run it bt_backtest = bt.Backtest(bt_strategy, price_data) bt_result = bt.run(bt_backtest) # Plot the backtest result bt_result.plot(title='Backtest result') plt.show()
def test_Results_helper_functions_fi(): names = ['foo', 'bar'] dates = pd.date_range(start='2017-01-01', end='2017-12-31', freq=pd.tseries.offsets.BDay()) n = len(dates) rdf = pd.DataFrame(np.zeros((n, len(names))), index=dates, columns=names) np.random.seed(1) rdf[names[0]] = np.random.normal(loc=0.1 / n, scale=0.2 / np.sqrt(n), size=n) rdf[names[1]] = np.random.normal(loc=0.04 / n, scale=0.05 / np.sqrt(n), size=n) pdf = 100 * np.cumprod(1 + rdf) notional = pd.Series(1e6, index=pdf.index) # algo to fire on the beginning of every month and to run on the first date runDailyAlgo = bt.algos.RunDaily(run_on_first_date=True) # algo to select all securities selectAll = bt.algos.SelectAll() # algo to set the weights # it will only run when runMonthlyAlgo returns true # which only happens on the first of every month weighRandomly = bt.algos.WeighRandomly() # algo to set the notional of the fixed income strategy setNotional = bt.algos.SetNotional('notional') # algo to rebalance the current weights to weights set by weighSpecified # will only run when weighSpecifiedAlgo returns true # which happens every time it runs rebalAlgo = bt.algos.Rebalance() # a strategy that rebalances monthly to specified weights strat = bt.FixedIncomeStrategy( 'random', [runDailyAlgo, selectAll, weighRandomly, setNotional, rebalAlgo]) backtest = bt.Backtest(strat, pdf, initial_capital=0, integer_positions=False, progress_bar=False, additional_data={ 'mydata': pdf, 'notional': notional }) bidoffer = 1. backtest2 = bt.Backtest(strat, pdf, initial_capital=0, integer_positions=False, progress_bar=False, additional_data={ 'mydata': pdf, 'notional': notional, 'bidoffer': pd.DataFrame(bidoffer, pdf.index, pdf.columns) }) random.seed(1234) res = bt.run(backtest) random.seed(1234) res2 = bt.run(backtest2) assert (type(res.get_security_weights()) is pd.DataFrame) assert (type(res.get_transactions()) is pd.DataFrame) assert len(res.get_transactions()) > 0 assert (type(res.get_weights()) is pd.DataFrame) # Make sure the insertion of the first row applies to additional data as well assert backtest.data.index.equals(backtest.additional_data['mydata'].index) # Check that bid/offer is accounted for transactions = res.get_transactions() transactions['price'] = transactions['price'] + 0.5 * bidoffer assert (res2.get_transactions().price - res2.get_transactions().price).abs().sum() == 0
import bt import matplotlib.pyplot as plt import pandas as pd data = bt.get('^NSEI', start='2016-01-01') #print data #sma = pd.rolling_mean(data,34) df = pd.DataFrame(data) #print df sma = df.rolling(window=34,center=False).mean() #print sma strategy = bt.Strategy('Price-MA Cross', [bt.algos.SelectWhere(data>sma), bt.algos.WeighEqually(), bt.algos.Rebalance() ]) test = bt.Backtest(strategy, data) result = bt.run(test) print result result.plot(), result.display() plt.show()
### Finds optimal SMA cross settings and return percentage # [best_low, best_high, best_percentage] = sma_cross_optimal_values(data, sma_low_bot, sma_low_top, sma_high_bot, sma_high_top, within_percentage) ### Get SMA based on the data # sma_low_plot = pd.rolling_mean(data, best_low) # sma_high_plot = pd.rolling_mean(data, best_high) # # plot = bt.merge(data, sma_low_plot, sma_high_plot).plot() ############################ ### Finds optimal SMA value for price crossing the SMA line # [best_sma, best_percentage] = above_sma_optimal_value(data, 5, sma_high_top, within_percentage) ### Get SMA based on the data # sma_best_plot = pd.rolling_mean(data, best_sma) # Do final test to print full results test = above_sma(data, best_sma) results = bt.run(test) # Display graphical plot of the data plot = bt.merge(data, sma_best_plot).plot() results.plot() results.display_monthly_returns() results.display() # Necessary to show matlibplot graphic produced with res.plot() plt.show() results.values()
def ema_cross(ticker: str, start_date: Union[str, datetime], other_args: List[str]): """Strategy where we go long/short when EMA(short) is greater than/less than EMA(short) Parameters ---------- ticker : str Stock to test start : Union[str, datetime] Backtest start date. Can be either string or datetime other_args : List[str] List of argparse arguments """ parser = argparse.ArgumentParser( add_help=False, formatter_class=argparse.ArgumentDefaultsHelpFormatter, prog="ema_cross", description= "Cross between a long and a short Exponential Moving Average.", ) parser.add_argument( "-l", "--long", default=50, dest="long", type=check_positive, help="Long EMA period", ) parser.add_argument( "-s", "--short", default=20, dest="short", type=check_positive, help="Short EMA period", ) parser.add_argument( "--spy", action="store_true", default=False, help="Flag to add spy hold comparison", dest="spy", ) parser.add_argument( "--no_bench", action="store_true", default=False, help="Flag to not show buy and hold comparison", dest="no_bench", ) parser.add_argument( "--no_short", action="store_false", default=True, dest="shortable", help="Flag that disables the short sell", ) try: ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: return if ns_parser.long < ns_parser.short: print("Short EMA period is longer than Long EMA period\n") return ticker = ticker.lower() # prices = bt.get(ticker, start=start_date) prices = get_data(ticker, start_date) short_ema = pd.DataFrame(ta.ema(prices[ticker], ns_parser.short)) short_ema.columns = [ticker] long_ema = pd.DataFrame(ta.ema(prices[ticker], ns_parser.long)) long_ema.columns = [ticker] # signals signals = long_ema.copy() signals[short_ema > long_ema] = 1.0 signals[short_ema <= long_ema] = -1.0 * ns_parser.shortable signals[long_ema.isnull()] = 0.0 combined_data = bt.merge(signals, prices, short_ema, long_ema) combined_data.columns = ["signal", "price", "ema_short", "ema_long"] bt_strategy = bt.Strategy( "EMA_Cross", [ bt.algos.WeighTarget(signals), bt.algos.Rebalance(), ], ) bt_backtest = bt.Backtest(bt_strategy, prices) if ns_parser.spy: spy_bt = buy_and_hold("spy", start_date, "SPY Hold") if ns_parser.no_bench: res = bt.run(bt_backtest, spy_bt) else: stock_bt = buy_and_hold(ticker, start_date, ticker.upper() + " Hold") res = bt.run(bt_backtest, spy_bt, stock_bt) else: if ns_parser.no_bench: res = bt.run(bt_backtest) else: stock_bt = buy_and_hold(ticker, start_date, ticker.upper() + " Hold") res = bt.run(bt_backtest, stock_bt) plot_bt(res, f"EMA Cross for EMA({ns_parser.short})/EMA({ns_parser.long})") print(res.display(), "\n") except Exception as e: print(e, "\n")
def simple_ema(ticker: str, start_date: Union[str, datetime], other_args: List[str]): """Strategy where stock is bought when Price > EMA(l) Parameters ---------- ticker : str Stock to test start : Union[str, datetime] Backtest start date. Can be either string or datetime other_args : List[str] List of argparse arguments """ parser = argparse.ArgumentParser( add_help=False, formatter_class=argparse.ArgumentDefaultsHelpFormatter, prog="ema", description="Strategy where stock is bought when Price > EMA(l)", ) parser.add_argument( "-l", default=20, dest="length", type=check_positive, help="EMA period to consider", ) parser.add_argument( "--spy", action="store_true", default=False, help="Flag to add spy hold comparison", dest="spy", ) parser.add_argument( "--no_bench", action="store_true", default=False, help="Flag to not show buy and hold comparison", dest="no_bench", ) try: ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: return ticker = ticker.lower() ema = pd.DataFrame() # prices = bt.get(ticker, start=start_date) # bt.get not working prices = get_data(ticker, start_date) ema[ticker] = ta.ema(prices[ticker], ns_parser.length) bt_strategy = bt.Strategy( "AboveEMA", [ bt.algos.SelectWhere(prices >= ema), bt.algos.WeighEqually(), bt.algos.Rebalance(), ], ) bt_backtest = bt.Backtest(bt_strategy, prices) if ns_parser.spy: spy_bt = buy_and_hold("spy", start_date, "SPY Hold") if ns_parser.no_bench: res = bt.run(bt_backtest, spy_bt) else: stock_bt = buy_and_hold(ticker, start_date, ticker.upper() + " Hold") res = bt.run(bt_backtest, spy_bt, stock_bt) else: if ns_parser.no_bench: res = bt.run(bt_backtest) else: stock_bt = buy_and_hold(ticker, start_date, ticker.upper() + " Hold") res = bt.run(bt_backtest, stock_bt) plot_bt(res, f"Equity for EMA({ns_parser.length})") print(res.display(), "\n") except Exception as e: print(e, "\n")
# Defining the actual strategy benchmark_strat = bt.Strategy(name, [ bt.algos.RunOnce(), bt.algos.SelectAll(), bt.algos.WeighEqually(), bt.algos.Rebalance() ]) # Make sure we're only running on the SPY data by selecting it out, # and dropping the rows for which we have no data spy_data = data[['SPY']] spy_data.dropna(inplace=True) # Generate the backtest using the defined strategy and data and run it benchmark_test = bt.Backtest(benchmark_strat, spy_data) res = bt.run(benchmark_test) # Print the summary and plot our equity progression res.plot() res.display() plt.show() ###### Strategy 1 ###### name = 'spy_virt_7030' strategy_1 = bt.Strategy(name, [ bt.algos.RunDaily(), bt.algos.SelectAll(), bt.algos.WeighSpecified(SPY=0.7, VIRT=0.3), bt.algos.Rebalance()
import bt import matplotlib matplotlib.get_backend() # download data from bt.algos import SelectWhere data = bt.get('aapl,msft', start='2016-01-01') # calculate moving average DataFrame using pandas' rolling_mean import pandas as pd # a rolling mean is a moving average, right? sma = pd.rolling_mean(data, 50) bt.merge(data, sma).plot(figsize=(15, 5)) signal = data > sma # first we create the Strategy s = bt.Strategy('above50sma', [SelectWhere(data > sma), bt.algos.WeighEqually(), bt.algos.Rebalance()]) # now we create the Backtest t = bt.Backtest(s, data) # and let's run it! res = bt.run(t) res.plot('d') print(type(res)) res.display()
def showResult(root_list, tickers_pool, prices_pool, savefig=False, prefix=None, train=True, i=None): if all(isinstance(root, str) for root in root_list): # test if ticker is converted tickers = root_list tickers_size = len(tickers) else: tickers = [tickers_pool[int(i)] for i in root_list] tickers_size = len(tickers) prices = prices_pool[tickers].dropna() equal = bt.Strategy('EqualWeight', algos=[ bt.algos.RunOnce(), bt.algos.SelectAll(), bt.algos.WeighEqually(), bt.algos.Rebalance(), ]) inverseVol = bt.Strategy('InverseVol', algos=[ bt.algos.RunMonthly(), bt.algos.SelectAll(), bt.algos.WeighInvVol(), ApplyLeverage(1.), bt.algos.Rebalance(), ]) try: backtest_equal = bt.Backtest(equal, prices) report = bt.run(backtest_equal) # backtest_inverese = bt.Backtest(inverseVol, prices) # report = bt.run(backtest_inverese) report_df = backtest.readReportCSV(report) if savefig: # prefix = f'{algorithm_param["max_num_iteration"]}_{algorithm_param["population_size"]}_' \ # f'{algorithm_param["max_iteration_without_improv"]}_{algorithm_param["mutation_probability"]}_' \ # f'{algorithm_param["elit_ratio"]}_{algorithm_param["crossover_probability"]}_{algorithm_param["parents_portion"]}_N' prefix = f'./{prefix}/' if train: if i is not None: suffix = f'_train_{i}.jpg' else: suffix = '_train.jpg' else: if i is not None: suffix = f'_test_{i}.jpg' else: suffix = '_test.jpg' plot_return = report.plot() plt.savefig(prefix + nameof(plot_return) + suffix) plot_weights = report.plot_security_weights() plt.savefig(prefix + nameof(plot_weights) + suffix) # plot_scatter_matrix = report.plot_scatter_matrix() # plt.savefig(nameof(plot_scatter_matrix)) plot_correlation = report.plot_correlation() plt.savefig(prefix + nameof(plot_correlation) + suffix) plot_histrograms = report.plot_histograms() plt.savefig(prefix + nameof(plot_histrograms) + suffix) plot_prices = prices.plot() plt.savefig(prefix + nameof(plot_prices) + suffix) plt.close('all') except Exception as e: print(e) print('The following calculation is wrong, please CHECK') print(tickers) print(prices) report_df = pd.DataFrame({ 'CAGR': [0], 'Calmar Ratio': 0, 'Daily Sharpe': 0, 'Win 12m %': '-' }) report_df = report_df.transpose() return report_df, tickers
return bt.Backtest(s, data) if __name__ == "__main__": # 获取数据 # data = getData() #data = bt.get("spy", start = "2010-01-01") #print(data.head()) #print(data.describe()) # SMA(data) #SMA_cross(data) t1 = sma_cross("aapl", name = "aapl_mass_cross") t2 = sma_cross("msft", name = "msft_mass_cross") res = bt.run(t1, t2) data = bt.merge(res["aapl_mass_cross"].prices, res["msft_mass_cross"].prices) s = bt.Strategy('s', [bt.algos.SelectAll(), bt.algos.WeighInvVol(), bt.algos.Rebalance() ]) t = bt.Backtest(s, data) res = bt.run(t) res.display() res.plot()
import bt # Download historical prices bt_data = bt.get('fb, amzn, goog, nflx, aapl', start='2020-6-1', end='2020-12-1') # Print the top five rows print(bt_data.head()) # Define the strategy bt_strategy = bt.Strategy('Trade_Weekly', [ bt.algos.RunWeekly(), bt.algos.SelectAll(), bt.algos.WeighEqually(), bt.algos.Rebalance() ]) # Create a backtest bt_test = bt.Backtest(bt_strategy, bt_data) # Run the backtest bt_res = bt.run(bt_test) # Plot the test result bt_res.plot(title="Backtest result") plt.show()
import bt import ffn # fetch some data data = bt.get('spy,agg', start='2010-01-01') print data.head() s = bt.Strategy('s1', [bt.algos.RunMonthly(), bt.algos.SelectAll(), bt.algos.WeighEqually(), bt.algos.Rebalance()]) # create a backtest and run it test = bt.Backtest(s, data) res = bt.run(test) res.plot() res.display() res.plot_weights() #print test.security_weights.tail(20) #print test.weights.tail(20) #print test.positions.tail(20) prices = ffn.get('aapl,msft', start='2010-01-01')
def rsi_strat(ticker: str, start_date: Union[datetime, str], other_args: List[str]): """Strategy that buys when the stock is less than a threshold and shorts when it exceeds a threshold. Parameters ---------- ticker : str Stock to test start : Union[str, datetime] Backtest start date. Can be either string or datetime other_args : List[str] List of argparse arguments """ parser = argparse.ArgumentParser( add_help=False, formatter_class=argparse.ArgumentDefaultsHelpFormatter, prog="rsi_strat", description="""Strategy that buys when the stock is less than a threshold and shorts when it exceeds a threshold.""", ) parser.add_argument( "-p", "--periods", dest="periods", help="Number of periods for RSI calculation", type=check_positive, default=14, ) parser.add_argument( "-u", "--high", default=70, dest="high", type=check_positive, help="High (upper) RSI Level", ) parser.add_argument("-l", "--low", default=30, dest="low", type=check_positive, help="Low RSI Level") parser.add_argument( "--spy", action="store_true", default=False, help="Flag to add spy hold comparison", dest="spy", ) parser.add_argument( "--no_bench", action="store_true", default=False, help="Flag to not show buy and hold comparison", dest="no_bench", ) parser.add_argument( "--no_short", action="store_false", default=True, dest="shortable", help="Flag that disables the short sell", ) try: ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: return if ns_parser.high < ns_parser.low: print("Low RSI value is higher than Low RSI value\n") return ticker = ticker.lower() # prices = bt.get(ticker, start=start_date) prices = get_data(ticker, start_date) rsi = pd.DataFrame(ta.rsi(prices[ticker], ns_parser.periods)) rsi.columns = [ticker] signal = 0 * rsi.copy() signal[rsi > ns_parser.high] = -1 signal[rsi < ns_parser.low] = 1 signal[rsi.isnull()] = 0 merged_data = bt.merge(signal, prices) merged_data.columns = ["signal", "price"] bt_strategy = bt.Strategy( "RSI Reversion", [bt.algos.WeighTarget(signal), bt.algos.Rebalance()]) bt_backtest = bt.Backtest(bt_strategy, prices) if ns_parser.spy: spy_bt = buy_and_hold("spy", start_date, "SPY Hold") if ns_parser.no_bench: res = bt.run(bt_backtest, spy_bt) else: stock_bt = buy_and_hold(ticker, start_date, ticker.upper() + " Hold") res = bt.run(bt_backtest, spy_bt, stock_bt) else: if ns_parser.no_bench: res = bt.run(bt_backtest) else: stock_bt = buy_and_hold(ticker, start_date, ticker.upper() + " Hold") res = bt.run(bt_backtest, stock_bt) plot_bt(res, f"RSI Strategy between ({ns_parser.low}, {ns_parser.high})") print(res.display(), "\n") except Exception as e: print(e, "\n")
# create a backtest and run it test = bt.Backtest(s, panel) test_s = bt.Backtest(ss, panel) test_r3_s = bt.Backtest(r3_s, panel) test_macd_s = bt.Backtest(macd_s, panel) test_ibs_s = bt.Backtest(ibs_s, panel) test_ibs_rsi_s = bt.Backtest(ibs_rsi_s, panel) sma10 = above_sma(data=panel, sma_per=10, name='sma10', start=start_date) sma20 = above_sma(data=panel, sma_per=20, name='sma20', start=start_date) sma40 = above_sma(data=panel, sma_per=40, name='sma40', start=start_date) benchmark = long_only_ew(data=bench_data, name='sh000001', start=start_date) long_only = long_only_ew(data=panel, name='bench', start=start_date) res = bt.run(test, test_s, sma10, sma20, sma40, benchmark, test_r3_s, test_macd_s, test_ibs_s, test_ibs_rsi_s) #res = bt.run(test_ibs_s, test, test_r3_s, test_macd_s, test_ibs_rsi_s, long_only) #trans = res.get_transactions() trans = [] if len(trans) > 0: res.plot() plt.show() res.plot_histogram() plt.show() print(trans.to_string()) # ok and what about some stats?
def run_backtest(backtests, prices): bts = [bt.Backtest(backtest, prices) for backtest in backtests] return bt.run(*bts)
def run_test(self): try: data = None if self.dataFileEdit.text(): try: cats = pd.read_excel(self.dataFileEdit.text(), sheet_name=1) sc = np.unique(cats.loc['Strategy']) if len(sc) <= len(colors.BASE_COLORS): scc = list(colors.BASE_COLORS.keys())[:len(sc)] else: scc = list(colors.CSS4_COLORS.keys())[:len(sc)] scd = {s: c for s, c in zip(sc, scc)} cats.loc['Colors'] = pd.Series({ i: scd[cats.loc['Strategy'][i]] for i in cats.loc['Strategy'].index }) am = np.unique(cats.loc['Asset']) ams = list('so^>v<dph8')[:len(am)] amd = {a: s for a, s in zip(am, ams)} cats.loc['Shapes'] = pd.Series({ i: amd[cats.loc['Asset'][i]] for i in cats.loc['Asset'].index }) except: cats = None date_column = self.dateColumnEdit.text( ) if self.dateColumnEdit.text() else 'Date' date_format = self.dateFormatEdit.text( ) if self.dateFormatEdit.text() else '%Y-%m-%d' data = pd.read_excel(self.dataFileEdit.text()) data = data.set_index( pd.DatetimeIndex( pd.to_datetime(data[date_column], format=date_format))) data = data.sort_index() data = data.drop(date_column, axis=1) data = data.sort_index() data = data.fillna(method='pad') idxs = None if self.startDateCBox.isChecked(): idxs = data.index >= self.startDatePicker.text() if self.endDateCBox.isChecked(): idxs = data.index <= self.endDatePicker.text( ) if idxs is None else (idxs) & ( data.index <= self.endDatePicker.text()) if idxs is not None: data = data.loc[idxs] if len(self._strategies) and data is not None: out_dir = self.reportFileEdit.text( ) if self.reportFileEdit.text() else dirname(__file__) if not exists(out_dir): makedirs(out_dir) backtests = [] rfs = dict() for s in self._strategies: if s.min_weight * data.shape[1] > s.leverage: raise Exception( 'Sum of min weights ({:.4f}) more than leverage ({:.4f})\n{}' .format(s.min_weight, s.leverage, str(s))) graph_dir = join(out_dir, s.name()) if exists(graph_dir): shutil.rmtree(graph_dir) makedirs(graph_dir) backtests.append(s.bt_strategy(data, cats, graph_dir)) rfs[s.name()] = s.risk_free res = bt.run(*backtests) perfs = dict() for s in self._strategies: k, v = s.name(), rfs[s.name()] fdate = data.index[0] + relativedelta( **{s.est_ptype: s.est_plen}) prices = res.backtests[k].strategy.prices if isinstance(v, str): v = pd.read_excel(v) v = v.set_index( pd.DatetimeIndex( pd.to_datetime(v[date_column], format=date_format))) v = v.sort_index() column = v.columns[1] v['Price'] = prices v = v.fillna(method='pad').fillna(0.0)[column] else: v = float(v) perfs[k] = PerformanceStats( prices.loc[prices.index >= fdate], v) stats = make_stats(perfs) bdf = { b.name: pd.concat( (b.strategy.data, b.weights, b.positions, b.turnover), axis=1) for b in backtests } pattern = re.compile('.*>') columns = backtests[0].strategy.data.columns.tolist() columns.extend([ 'W_' + pattern.sub('', c) for c in backtests[0].weights.columns ]) columns.extend([ 'POS_' + pattern.sub('', c) for c in backtests[0].positions.columns ]) columns.append('Turnover') writer = pd.ExcelWriter(join(out_dir, 'hrp_results.xlsx')) stats.to_excel(writer, 'Stats') res.prices.to_excel(writer, 'Prices') res.lookback_returns.applymap(fmtp).to_excel( writer, 'Lookback') for name, df in bdf.items(): df.columns = columns df.to_excel(writer, name) writer.save() qtw.QMessageBox.information(self, "I'm ready", "I'm ready") else: qtw.QMessageBox.critical(self, "No strategies", "Add strategies") except: qtw.QMessageBox.critical(self, 'Something wrong T_T', str(sys.exc_info())) traceback.print_tb(sys.exc_info()[2])
def run_strategy(*strategy): return bt.run(*strategy)
strategy_ = bt.Strategy('Your Strategy None', [ bt.algos.RunOnce(), bt.algos.SelectAll(), bt.algos.WeighSpecified(**stock_dic), bt.algos.Rebalance() ]) #Creating strategy strategy_control = bt.Strategy('60-40 None', [ bt.algos.RunOnce(), bt.algos.SelectAll(), bt.algos.WeighSpecified(**stock_dic_control), bt.algos.Rebalance() ]) #Creating strategy test_control = bt.Backtest(strategy_control, data) results_control = bt.run(test_control) test_spy = bt.Backtest(strategy_spy, data) results_spy = bt.run(test_spy) test_agg = bt.Backtest(strategy_agg, data) results_agg = bt.run(test_agg) test = bt.Backtest(strategy_, data) results = bt.run(test) #Line Chart ser = results._get_series( None).rebase() #gets all the daily balances as a series ser2 = results_control._get_series(None).rebase()
@author: cortinamatthieu """ import bt ##récupération du SP500 pour comparer nos stratégies au marché## data_spy = bt.get('spy', start='2012-03-01', end='2014-01-01') s_spy = bt.Strategy('S&P 500 only', [ bt.algos.RunMonthly(), bt.algos.SelectThese(['spy']), bt.algos.WeighEqually(), bt.algos.Rebalance() ]) b_spy = bt.Backtest(s_spy, data_spy) result = bt.run(b_spy) result.plot() ############################################################### ############################################################### ####on récup le taux sans risque### riskfree = bt.get('IEF', start='2012-03-01', end='2014-01-01') riskfree_rate = float(riskfree.calc_cagr()) import quandl ####on importe les données#### equity_list = ['AAPL', 'IBM', 'NKE', 'GM', 'MCD'] wiki_equity_list = [] for ticker in equity_list: wiki_equity_list.append('WIKI/' + ticker)
import bt import matplotlib.pyplot as plt data = bt.get('spy,agg', start='2010-01-01') s = bt.Strategy('s1', [ bt.algos.RunMonthly(), bt.algos.SelectAll(), bt.algos.WeighEqually(), bt.algos.Rebalance() ]) test = bt.Backtest(s, data) res = bt.run(test) res.plot() plt.show()
def spread_crossover(data_df,slow=1,fast=12): spread_log = pd.DataFrame(np.log(data_df.ix[:,0] * 100)) data_df['spread_z_ma'] = (spread_log - pd.expanding_mean(spread_log, min_periods=24))/ pd.expanding_std(spread_log, min_periods=24) data_df['spread_z_ema'] = (spread_log - pd.ewma(spread_log, min_periods = 24, halflife=12)) / pd.ewmstd(spread_log, halflife=12) data_df['spread_z_ema'] = pd.rolling_mean(data_df['spread_z_ema'], window=3) data_df['slow'] = pd.rolling_mean(data_df['US HY Spread'],slow) data_df['fast'] = pd.rolling_mean(data_df['US HY Spread'],fast) data_df['diff'] = (data_df['slow'] - data_df['fast']) * -1 data_df['diff'] = data_df['diff'] + 1 data_df['diff'] = np.log(data_df['diff']) data_df['tren_z_ma'] = (data_df['diff'] - pd.expanding_mean(data_df['diff'], min_periods=24))/ pd.expanding_std(data_df['diff'], min_periods=24) data_df['tren_z_ma'] = pd.rolling_mean(data_df['tren_z_ma'], window=3) trend_valuation_df = pd.concat([data_df['spread_z_ema'],data_df['tren_z_ma']], axis=1) trend_valuation_df.dropna(inplace=True) trend_valuation_df.plot() plt.show() algo_wghts_df = pd.DataFrame() wghts_array = [] valuation_threshold_cheap = 1 valuation_threshold_rich = -1.0 trend_threshold_tightening = 0.1 trend_threshold_widening = -0.1 data_df['spread_z_ma'].plot() plt.show() for score in trend_valuation_df.values: valuation_score = score[0] trend_score = score[1] if (trend_score >= -0.2 and valuation_score >= -1): wghts_array.append(min(1,abs(trend_score-valuation_score) / 1)) else: wghts_array.append(0) #elif trend_score <= -0.1 and valuation_score <= valuation_threshold_cheap: # wghts_array.append(-1) #elif valuation_score >= valuation_threshold_cheap: # wghts_array.append(1) #else: # wghts_array.append(0) wghts_df = pd.DataFrame(wghts_array, index = trend_valuation_df.index) long = wghts_df[wghts_df == 1].count()[0] / len(trend_valuation_df) neutral = wghts_df[wghts_df == 0].count()[0] / len(trend_valuation_df) short = wghts_df[wghts_df == -1].count()[0] / len(trend_valuation_df) wghts_df.columns = [data_df.columns.values[1]] wghts_df = wghts_df.shift(1) s1 = bt.Strategy('Valuation & Trend ', [bt.algos.WeighTarget(wghts_df), bt.algos.Rebalance()]) return_data = data_df.ix[:,1].to_frame() return_data.columns = [data_df.columns.values[1]] strategy = bt.Backtest(s1, return_data) res = bt.run(strategy) res.plot(logy=True) res.display() print(long,neutral,short)
def test_RenomalizedFixedIncomeResult(): dts = pd.date_range('2010-01-01', periods=5) data = pd.DataFrame(index=dts, columns=['a'], data=1.) data['a'][dts[0]] = 0.99 data['a'][dts[1]] = 1.01 data['a'][dts[2]] = 0.99 data['a'][dts[3]] = 1.01 data['a'][dts[4]] = 0.99 weights = pd.DataFrame(index=dts, columns=['a'], data=1.) weights['a'][dts[0]] = 1. weights['a'][dts[1]] = 2. weights['a'][dts[2]] = 1. weights['a'][dts[3]] = 2. weights['a'][dts[4]] = 1. coupons = pd.DataFrame(index=dts, columns=['a'], data=0.) algos = [ bt.algos.SelectAll(), bt.algos.WeighTarget(weights), bt.algos.SetNotional('notional'), bt.algos.Rebalance() ] children = [bt.CouponPayingSecurity('a')] s = bt.FixedIncomeStrategy('s', algos, children=children) t = bt.Backtest(s, data, initial_capital=0, additional_data={ 'notional': pd.Series(1e6, dts), 'coupons': coupons }, progress_bar=False) res = bt.run(t) t = res.backtests['s'] # Due to the relationship between the time varying notional and the prices, # the strategy has lost money, but price == 100, so "total return" is zero assert t.strategy.value < 0. assert t.strategy.price == 100. assert res.stats['s'].total_return == 0 # Renormalizing results to a constant size "fixes" this norm_res = bt.backtest.RenormalizedFixedIncomeResult( 1e6, *res.backtest_list) aae(norm_res.stats['s'].total_return, t.strategy.value / 1e6, 16) # Check that using the lagged notional value series leads to the same results # as the original calculation. This proves that we can re-derive the price # series from the other data available on the strategy notl_values = t.strategy.notional_values.shift(1) notl_values[ dts[0]] = 1e6 # The notional value *before* any trades are put on norm_res = bt.backtest.RenormalizedFixedIncomeResult( notl_values, *res.backtest_list) assert norm_res.stats['s'].total_return == res.stats['s'].total_return assert norm_res.prices.equals(res.prices)
# algo to fire on the beginning of every month and to run on the first date runMonthlyAlgo = bt.algos.RunMonthly(run_on_first_date=True, run_on_end_of_period=True) # algo to set the weights in the temp dictionary\ weights = pd.Series([0.6, 0.4, 0.], index=rdf.columns) weighSpecifiedAlgo = bt.algos.WeighSpecified(**weights) # algo to rebalance the current weights to weights set in temp dictionary rebalAlgo = bt.algos.Rebalance() # a strategy that rebalances monthly to specified weights s = 'monthly' strat = bt.Strategy(s, [runMonthlyAlgo, weighSpecifiedAlgo, rebalAlgo]) """ runMonthlyAlgo will return True on the last day of the month. If runMonthlyAlgo returns True, then weighSpecifiedAlgo will set the weights and return True. If weighSpecifiedAlgo returns True, then rebalAlgo will rebalance the portfolio to match the target weights. """ # set integer_positions=False when positions are not required to be integers(round numbers) backtest = bt.Backtest(strat, pdf, integer_positions=False) res = bt.run(backtest) # set riskfree as the rf index res.set_riskfree_rate(pdf['rf']) wait = 1
df['NewIndex'] = df['NewIndex'] + constant df['NI_maShort'] = df['NewIndex'].rolling(maShort).mean() df['NI_maLong'] = df['NewIndex'].rolling(maLong).mean() weights = df.copy(deep=True) weights.dropna(inplace=True) weights['FXF1'] = weights['NI_maShort'] > weights['NI_maLong'] weights['FXF1'] = weights['FXF1'].replace({True: -1*fw, False: fw}) weights['EXF1'] = weights['NI_maShort'] > weights['NI_maLong'] weights['EXF1'] = weights['EXF1'].replace({True: ew, False: -1*ew}) weights = weights[['FXF1', 'EXF1']] s = bt.Strategy('EnF', [ bt.algos.SelectAll(), bt.algos.WeighTarget(weights=weights), bt.algos.Rebalance() ]) t = bt.Backtest(s, df[['FXF1', 'EXF1']].loc[df.index > start_date]) res = bt.run(t) print('\n', res.display()) now = datetime.datetime.now() file_dst = sys.path[0] + '/result/EnF-%s.pkl' % now with open(file_dst, 'wb') as f: pickle.dump(res, f, protocol=pickle.HIGHEST_PROTOCOL) file_dst = sys.path[0] + '/trade/EnF-%s.pkl' % now with open(file_dst, 'wb') as f: pickle.dump(t, f, protocol=pickle.HIGHEST_PROTOCOL)
# Fetch some data for the benchmark SP500 data_sp500 = bt.get('spy,agg', start=b, end=b + offset) # Recreate the strategy for the SP500, we use here an Equally Weighted strategy b_sp500 = bt.Strategy('SP500', [ bt.algos.RunOnce(), bt.algos.SelectAll(), bt.algos.WeighEqually(), bt.algos.Rebalance() ]) # Create a backtest named for the SP500 sp500_test = bt.Backtest(b_sp500, data_sp500) #we run the backtest and get some results result = bt.run(b_mark, sp500_test) #create the run only for the b_mark result_1 = bt.run( b_mark) #we need this result to get the return distribution later #result = bt.run(b_mark, b_inv, b_random, b_best, b_sp500) result.set_riskfree_rate(riskfree_rate) result.plot() #show histogram based on the result_1 run, as we can't get the return distribution from the first run including the benchmark result_1.plot_histograms(bins=50, figsize=(20, 10)) # Show some performance metrics result.display()
# here we will set the weight to 0 - this is because the sma_long needs long data points before # calculating its first point. Therefore, it will start with a bunch of nulls (NaNs). # This fills up the Not a Numbers (NaNs) with 0.0 instead # If we left the NaNs, we would get an error when we tried to do math without a number target_weights_s1[sma_short_s1.isnull()] = 0.0 target_weights_s2[sma_short_s2.isnull()] = 0.0 # Now set up the MA_cross strategy for our moving average cross strategy MA_cross = bt.Strategy( 'MA_cross', [bt.algos.WeighTarget(target_weights_s1), bt.algos.Rebalance()]) test_MA = bt.Backtest(MA_cross, data) res_MA = bt.run(test_MA) # plot security weights to test logic res_MA.plot_security_weights() plt.title(label="SMA from 50 to 200", fontsize=25) # signal = data > sma_32 MA_cross_2 = bt.Strategy( 'MA_cross_2', [bt.algos.WeighTarget(target_weights_s2), bt.algos.Rebalance()]) test_MA_2 = bt.Backtest(MA_cross_2, data) res_MA_2 = bt.run(test_MA_2)
def ticker (tickertxt): ticker = tickertxt today = date.today ().strftime ("%Y-%m-%d") stock_data = yf.download (ticker , start="2020-1-1" , end=today) st.table(stock_data.tail()) EMA_short = talib.EMA (stock_data['Close'] , timeperiod=12).to_frame () EMA_short = EMA_short.rename (columns={0: 'Close'}) EMA_long = talib.EMA (stock_data['Close'] , timeperiod=50).to_frame () EMA_long = EMA_long.rename (columns={0: 'Close'}) signal = EMA_long.copy () signal[EMA_long.isnull ()] = 0 signal[EMA_short > EMA_long] = 1 signal[EMA_short < EMA_long] = -1 #print(type(signal)) st.markdown(signal[50:250]) transition = signal[signal['Close'].diff() != 0] buy_signal = transition[transition['Close'] == 1] sell_signal = transition[transition['Close'] == -1] buy_index = buy_signal.index buy_position = stock_data[stock_data.index.isin(buy_index)] sell_index = sell_signal.index sell_position = stock_data[stock_data.index.isin(sell_index)] fig = go.Figure() fig.add_trace( go.Candlestick(x=stock_data.index, open=stock_data['Open'], high=stock_data['High'], low=stock_data['Low'], close=stock_data['Close'], name="Stock Prices" ) ) fig.add_trace( go.Scatter( x=stock_data.index, y=EMA_long['Close'], name="EMA 50" ) ) fig.add_trace( go.Scatter( x=stock_data.index, y=EMA_short['Close'], name = "EMA 12" ) ) fig.add_trace( go.Scatter( x=buy_position.index, y=buy_position['Close'], name="Buy Signal", marker=dict(color="#511CFB", size=15), mode="markers", marker_symbol="triangle-up" ) ) fig.add_trace( go.Scatter( x=sell_position.index, y=sell_position['Close'], name="Sell Signal", marker=dict(color="#750086", size=15), mode="markers", marker_symbol="triangle-down" ) ) fig.update_layout( xaxis_rangeslider_visible=False, title="Daily Close (" + ticker + ") Prices", xaxis_title="Date", yaxis_title="Price (USD)" ) st.plotly_chart (fig , use_container_width=True) # # # #get_ipython().run_line_magic('matplotlib', 'inline') # bt_strategy = bt.Strategy('EMA_crossover', [ bt.algos.RunWeekly(), bt.algos.WeighTarget(signal), bt.algos.Rebalance() ] ) bt_backtest = bt.Backtest (bt_strategy , stock_data['Close'].to_frame ()) bt_result = bt.run (bt_backtest) bt_result.plot (title='Backtest result (Equity Progression)') st.pyplot (plt , use_container_width=True) bt_result.plot_histograms(bins=50, freq = 'w') st.pyplot (plt , use_container_width=True) # # print("Type",type(bt_result.display())) # print(bt_result.to_csv().replace(",,,,,,,,,,,,,,,,,",",")) cwd =os.getcwd() data = bt_result.to_csv(cwd+"/blabla.csv").replace(",,,,,,,,,,,,,,,,,",",") # print(data) # print(pd.read_csv(data. split(sep="\n"))) # bt_result.to_csv(sep=";",path="/Users/karlestermann/PycharmProjects/StreamlitDemoCyrus/blabla.csv").replace(",,,,,,,,,,,,,,,,,",",") data1 = pd.read_csv(cwd+"/blabla.csv",sep=",",skip_blank_lines=True,na_values=None) # print(data1) st.table(data1)
def backtest_single(weight_series, price_series, name, my_comm, verbose=False): baseline = bt.Strategy(name, [WeighTarget(weight_series), bt.algos.Rebalance()]) result = bt.run(bt.Backtest(baseline, price_series, progress_bar=verbose, commissions=my_comm)) return result