from haasomeapi.HaasomeClient import HaasomeClient from haasomeapi.apis.MarketDataApi import MarketDataApi from haasomeapi.enums.EnumPriceSource import EnumPriceSource from haasomeapi.enums.EnumErrorCode import EnumErrorCode from haasomeapi.enums.EnumCustomBotType import EnumCustomBotType from haasomeapi.dataobjects.custombots.BaseCustomBot import BaseCustomBot from botdatabase import BotDB import configserver from backtesting import Backtest ,Strategy from MarketDataClass import MarketData as md from backtesting.lib import SignalStrategy, TrailingStrategy # from MadHatterBotClass import MadHatterBot as mh # from botdb import BotDB as bdb md = md() md = md.read_csv( '/Users/cosmos/GitHub/Haasomeapitools/haasomeapitools/market_data/BITFINEX|ABS|USD.csv') print(md) bt = Backtest(data=md, strategy=SignalStrategy()).run()
def test_data_invalid(self): with self.assertRaises(TypeError): Backtest(GOOG.index, SmaCross).run() with self.assertRaises(ValueError): Backtest(GOOG.iloc[:0], SmaCross).run()
def test_broker_params(self): bt = Backtest(GOOG.iloc[:100], SmaCross, cash=1000, commission=.01, margin=.1, trade_on_close=True) bt.run()
self.buy() elif crossover(self.sma2, self.sma1): self.sell() # In[ ]: # In[ ]: # In[ ]: # In[91]: bt = Backtest(STOCK, SmaCross, cash=1000, commission=.002, exclusive_orders=True) output = bt.run() bt.plot() # In[92]: output # In[ ]: # In[ ]: # In[ ]:
from backtesting import Backtest, Strategy from backtesting.lib import crossover from backtesting.test import SMA, GOOG class SmaCross(Strategy): def init(self): price = self.data.Close self.ma1 = self.I(SMA, price, 10) self.ma2 = self.I(SMA, price, 20) def next(self): if crossover(self.ma1, self.ma2): self.buy() elif crossover(self.ma2, self.ma1): self.sell() bt = Backtest(GOOG, SmaCross, commission=.002, exclusive_orders=True) stats = bt.run() bt.plot()
def test_run_invalid_param(self): bt = Backtest(GOOG, SmaCross) self.assertRaises(AttributeError, bt.run, foo=3)
def test_data_missing_columns(self): df = GOOG.copy(deep=False) del df['Open'] with self.assertRaises(ValueError): Backtest(df, SmaCross).run()
from backtesting.test import SMA import GetSecurityInfo as GetSecurityInfo class SmaCross(Strategy): n1 = 10 n2 = 20 def init(self): close = self.data.Close self.sma1 = self.I(SMA, close, self.n1) self.sma2 = self.I(SMA, close, self.n2) def next(self): if crossover(self.sma1, self.sma2): self.buy() elif crossover(self.sma2, self.sma1): self.sell() bt = Backtest(GetSecurityInfo.GetSecurityInfo(2618, "1d", "20100101", "20210312"), SmaCross, cash=10000, commission=.002, exclusive_orders=True) print(bt.run()) bt.plot()
# **Note**: `self.data` and any indicators wrapped with `self.I` (e.g. `self.sma1`) are NumPy arrays for performance reasons. If you prefer pandas Series or DataFrame objects, use `Strategy.data.<column>.s` or `Strategy.data.df` accessors respectively. You could also construct the series manually, e.g. `pd.Series(self.data.Close, index=self.data.index)`. # # We might avoid `self.position.close()` calls if we primed the # [`Backtest`](https://kernc.github.io/backtesting.py/doc/backtesting/backtesting.html#backtesting.backtesting.Backtest) # instance with `Backtest(..., exclusive_orders=True)`. # ## Backtesting # # Let's see how our strategy performs on historical Google data. The # [`Backtest`](https://kernc.github.io/backtesting.py/doc/backtesting/backtesting.html#backtesting.backtesting.Backtest) # instance is initialized with OHLC data and a strategy _class_ (see API reference for additional options), and we begin with 10,000 units of cash and set broker's commission to realistic 0.2%. # + from backtesting import Backtest bt = Backtest(GOOG, SmaCross, cash=10000, commission=.002) stats = bt.run() stats # - # [`Backtest.run()`](https://kernc.github.io/backtesting.py/doc/backtesting/backtesting.html#backtesting.backtesting.Backtest.run) # method returns a pandas Series of simulation results and statistics associated with our strategy. We see that this simple strategy makes almost 600% return in the period of 9 years, with maximum drawdown 33%, and with longest drawdown period spanning almost two years ... # # [`Backtest.plot()`](https://kernc.github.io/backtesting.py/doc/backtesting/backtesting.html#backtesting.backtesting.Backtest.plot) # method provides the same insights in a more visual form. bt.plot() # ## Optimization # # We hard-coded the two lag parameters (`n1` and `n2`) into our strategy above. However, the strategy may work better with 15–30 or some other cross-over. **We declared the parameters as optimizable by making them [class variables](https://docs.python.org/3/tutorial/classes.html#class-and-instance-variables)**.
and crossover(self.data.Close, self.sma_exit)): self.position.close() # - # It's not a robust strategy, but we can optimize it. Let's optimize our strategy on Google stock data. # + # %%time from backtesting import Backtest from backtesting.test import GOOG backtest = Backtest(GOOG, Sma4Cross, commission=.002) stats, heatmap = backtest.optimize( n1=range(10, 110, 10), n2=range(20, 210, 20), n_enter=range(15, 35, 5), n_exit=range(10, 25, 5), constraint=lambda p: p.n_exit < p.n_enter < p.n1 < p.n2, maximize='Equity Final [$]', return_heatmap=True) # - # Notice `return_heatmap=True` parameter passed to # [`Backtest.optimize()`](https://kernc.github.io/backtesting.py/doc/backtesting/backtesting.html#backtesting.backtesting.Backtest.optimize). # It makes the function return a heatmap series along with the usual stats of the best run. # `heatmap` is a pandas Series indexed with a MultiIndex, a cartesian product of all permissible parameter values.
from backtesting import Backtest import pandas as pd from backtesting import Strategy from backtesting.lib import crossover from backtesting.lib import SignalStrategy, TrailingStrategy import talib def run_strategy(strategy: Strategy, data: pd.DataFrame, cash: int = 10_000, commission: float = .002): """run the backtest for a specific strategy Args: strategy (Strategy): The strategy you want to execute path (pd.DataFrame): the data to backtest cash (int, optional): the entry cash you will have. Defaults to 10_000. commission (float, optional): the broker commision. Defaults to .002. """ bt = Backtest(data, strategy, cash=10_000, commission=.002) stats = bt.run() print(stats) print(bt.plot())
def hisse(request, name): bt = Backtest(GOOG, SmaCross, cash=10000, commission=.002) name = bt.run() html = "<html><body>It is now %s.</body></html>" % name return HttpResponse(html)
# Buy at market price on next open, but do # set 8% fixed stop loss. self.buy(sl=.92 * price) # If the price closes 2% or more below 10-day MA # close the position, if any. elif price < .98 * self.ma10[-1]: self.position.close() # - # Let's see how our strategy fares replayed on nine years of Google stock data. # + from backtesting.test import GOOG backtest = Backtest(GOOG, System, commission=.002) backtest.run() # - # Meager four trades in the span of nine years and with zero return? How about if we optimize the parameters a bit? # + # %%time backtest.optimize(d_rsi=range(10, 35, 5), w_rsi=range(10, 35, 5), level=range(30, 80, 10)) # - backtest.plot()
def test_compute_drawdown(self): dd = pd.Series([0, 1, 7, 0, 4, 0, 0]) durations, peaks = Backtest._compute_drawdown_duration_peaks(dd) np.testing.assert_array_equal(durations, pd.Series([3, 2], index=[3, 5]).reindex(dd.index)) np.testing.assert_array_equal(peaks, pd.Series([7, 4], index=[3, 5]).reindex(dd.index))
def test_file_size(self): bt = Backtest(GOOG, SmaCross) bt.run() with _tempfile() as f: bt.plot(filename=f[:-len('.html')], open_browser=False) self.assertLess(os.path.getsize(f), 500000)
from backtesting import Backtest, Strategy from backtesting.lib import crossover import pandas from backtesting.test import MACD, GOOG binance_data = pandas.read_csv('backtest/data/binance-btc-usd.csv') class MacdCross(Strategy): def init(self): price = self.data.Close self.macd, self.macd_signal, self.macd_histogram = self.I( MACD, price, 12, 26, 9) def next(self): if crossover(self.macd, self.macd_signal): self.buy() elif crossover(self.macd_signal, self.macd): self.sell() bt = Backtest(binance_data, MacdCross, commission=.002, exclusive_orders=True, cash=10_000) stats = bt.run() print(stats) # bt.plot()
def test_run(self): bt = Backtest(EURUSD, SmaCross) bt.run()
def test_assertions(self): class Assertive(Strategy): def init(self): self.sma = self.I(SMA, self.data.Close, 10) self.remains_indicator = np.r_[2] * np.cumsum(self.sma * 5 + 1) * np.r_[2] resampled = resample_apply('W', SMA, self.data.Close, 3) resampled_ind = resample_apply('W', SMA, self.sma, 3) assert np.unique(resampled[-5:]).size == 1 assert np.unique(resampled[-6:]).size == 2 assert resampled in self._indicators, "Strategy.I not called" assert resampled_ind in self._indicators, "Strategy.I not called" try: self.data.X except KeyError: pass else: assert False assert self.data.pip == .01 assert float(self.data.Close) == self.data.Close[-1] def next(self, FIVE_DAYS=pd.Timedelta('3 days')): assert self.equity >= 0 assert isinstance(self.sma, _Indicator) assert isinstance(self.remains_indicator, _Indicator) assert self.remains_indicator.name assert isinstance(self.remains_indicator._opts, dict) assert not np.isnan(self.data.Open[-1]) assert not np.isnan(self.data.High[-1]) assert not np.isnan(self.data.Low[-1]) assert not np.isnan(self.data.Close[-1]) assert not np.isnan(self.data.Volume[-1]) assert not np.isnan(self.sma[-1]) assert self.data.index[-1] self.orders.is_long self.orders.is_short self.orders.entry self.orders.sl self.orders.tp self.position self.position.size self.position.pl self.position.pl_pct self.position.open_price self.position.open_time self.position.is_long if crossover(self.sma, self.data.Close): self.orders.cancel() self.sell() assert not self.orders.is_long assert self.orders.is_short assert self.orders.entry assert not self.orders.sl assert not self.orders.tp price = self.data.Close[-1] sl, tp = 1.05 * price, .9 * price self.sell(price, sl=sl, tp=tp) self.orders.set_entry(price) self.orders.set_sl(sl) self.orders.set_tp(tp) assert self.orders.entry == price assert self.orders.sl == sl assert self.orders.tp == tp elif self.position: assert not self.orders.entry assert not self.position.is_long assert not not self.position.is_short assert self.position.open_price assert self.position.pl assert self.position.pl_pct assert self.position.size < 0 if self.data.index[ -1] - self.position.open_time > FIVE_DAYS: self.position.close() bt = Backtest(GOOG, Assertive) stats = bt.run() self.assertEqual(stats['# Trades'], 144)
def test_run_speed(self): bt = Backtest(GOOG, SmaCross) start = time.process_time() bt.run() end = time.process_time() self.assertLess(end - start, .2)
def test_compute_stats(self): stats = Backtest(GOOG, SmaCross).run() # Pandas compares in 'almost equal' manner from pandas.testing import assert_series_equal assert_series_equal( stats.filter(regex='^[^_]').sort_index(), pd.Series({ # NOTE: These values are also used on the website! '# Trades': 65, 'Avg. Drawdown Duration': pd.Timedelta('41 days 00:00:00'), 'Avg. Drawdown [%]': -6.087158560194047, 'Avg. Trade Duration': pd.Timedelta('46 days 00:00:00'), 'Avg. Trade [%]': 3.0404430275631444, 'Best Trade [%]': 54.05363186670138, 'Buy & Hold Return [%]': 703.4582419772772, 'Calmar Ratio': 0.0631443286380662, 'Duration': pd.Timedelta('3116 days 00:00:00'), 'End': pd.Timestamp('2013-03-01 00:00:00'), 'Equity Final [$]': 52624.29346696951, 'Equity Peak [$]': 76908.27001642012, 'Expectancy [%]': 8.774692825628644, 'Exposure [%]': 93.93453145057767, 'Max. Drawdown Duration': pd.Timedelta('584 days 00:00:00'), 'Max. Drawdown [%]': -48.15069053929621, 'Max. Trade Duration': pd.Timedelta('183 days 00:00:00'), 'Return [%]': 426.2429346696951, 'SQN': 0.91553210127173, 'Sharpe Ratio': 0.23169782960690408, 'Sortino Ratio': 0.7096713270577958, 'Start': pd.Timestamp('2004-08-19 00:00:00'), 'Win Rate [%]': 46.15384615384615, 'Worst Trade [%]': -18.85561318387153, }).sort_index()) self.assertTrue( stats._trade_data.columns.equals( pd.Index([ 'Equity', 'Exit Entry', 'Exit Position', 'Entry Price', 'Exit Price', 'P/L', 'Returns', 'Drawdown', 'Drawdown Duration' ])))
def test_data_nan_columns(self): df = GOOG.copy() df['Open'] = np.nan with self.assertRaises(ValueError): Backtest(df, SmaCross).run()
def test_optimize_invalid_param(self): bt = Backtest(GOOG.iloc[:100], SmaCross) self.assertRaises(AttributeError, bt.optimize, foo=range(3))
from backtesting import Backtest, Strategy from backtesting.lib import crossover from backtesting.test import SMA, GOOG class SmaCross(Strategy): n1 = 10 n2 = 30 def init(self): self.sma1 = self.I(SMA, self.data.Close, self.n1) self.sma2 = self.I(SMA, self.data.Close, self.n2) def next(self): if crossover(self.sma1, self.sma2): self.buy() elif crossover(self.sma2, self.sma1): self.sell() if __name__ == '__main__': # Windows: avoid concurrent.futures.process.BrokenProcessPool by wrapping in this if __name__ section bt = Backtest(GOOG, SmaCross, cash=10000, commission=.002) output = bt.run() print(output) bt.optimize(n1=range(5, 20, 5), n2=range(10, 100, 10),) bt.plot()
def test_optimize_no_trades(self): bt = Backtest(GOOG, SmaCross) stats = bt.optimize(fast=[3], slow=[3]) self.assertTrue(stats.isnull().any())
# Load dataframes natdf = pkl.load(open('XXXNATDFXXX', 'rb')) endf = pkl.load(open('XXXENDFXXX', 'rb')) # Find max length of df max = natdf.shape[0] if max > endf.shape[0]: max = endf.shape[0] # Create backtest based on df data comm = XXXCOMMXXX * 0.01 bt = Backtest(natdf.tail(max), XXXNAMEXXX, cash=XXXCASHXXX, commission=comm, margin=XXXMARGINXXX) # Run backtest sts are the returned stats sts = bt.run() sts.to_csv('XXXRESULTXXXX') # Optimization based on Strategy class variables # optstats = bt.optimize(SL=range(1,5,1),TP=range(1,5,1)) # optstats = bt.optimize(SMAPER=range(7,98,7)) # print(optstats) # Quantstats report https://github.com/ranaroussi/quantstats # Create up Buy and Hold returns hodler = natdf['Close'].tail(max).pct_change()
def test_optimize_speed(self): bt = Backtest(GOOG.iloc[:100], SmaCross) start = time.process_time() bt.optimize(fast=(2, 5, 7), slow=[10, 15, 20, 30]) end = time.process_time() self.assertLess(end - start, .2)
def test_assertions(self): class Assertive(Strategy): def init(self): self.sma = self.I(SMA, self.data.Close, 10) self.remains_indicator = np.r_[2] * np.cumsum(self.sma * 5 + 1) * np.r_[2] self.transpose_invalid = self.I(lambda: np.column_stack((self.data.Open, self.data.Close))) resampled = resample_apply('W', SMA, self.data.Close, 3) resampled_ind = resample_apply('W', SMA, self.sma, 3) assert np.unique(resampled[-5:]).size == 1 assert np.unique(resampled[-6:]).size == 2 assert resampled in self._indicators, "Strategy.I not called" assert resampled_ind in self._indicators, "Strategy.I not called" assert 1 == try_(lambda: self.data.X, 1, AttributeError) assert 1 == try_(lambda: self.data['X'], 1, KeyError) assert self.data.pip == .01 assert float(self.data.Close) == self.data.Close[-1] def next(self, FIVE_DAYS=pd.Timedelta('3 days')): assert self.equity >= 0 assert isinstance(self.sma, _Indicator) assert isinstance(self.remains_indicator, _Indicator) assert self.remains_indicator.name assert isinstance(self.remains_indicator._opts, dict) assert not np.isnan(self.data.Open[-1]) assert not np.isnan(self.data.High[-1]) assert not np.isnan(self.data.Low[-1]) assert not np.isnan(self.data.Close[-1]) assert not np.isnan(self.data.Volume[-1]) assert not np.isnan(self.sma[-1]) assert self.data.index[-1] self.position self.position.size self.position.pl self.position.pl_pct self.position.is_long if crossover(self.sma, self.data.Close): self.orders.cancel() # cancels only non-contingent price = self.data.Close[-1] sl, tp = 1.05 * price, .9 * price n_orders = len(self.orders) self.sell(size=.21, limit=price, stop=price, sl=sl, tp=tp) assert len(self.orders) == n_orders + 1 order = self.orders[-1] assert order.limit == price assert order.stop == price assert order.size == -.21 assert order.sl == sl assert order.tp == tp assert not order.is_contingent elif self.position: assert not self.position.is_long assert self.position.is_short assert self.position.pl assert self.position.pl_pct assert self.position.size < 0 trade = self.trades[0] if self.data.index[-1] - self.data.index[trade.entry_bar] > FIVE_DAYS: assert not trade.is_long assert trade.is_short assert trade.size < 0 assert trade.entry_bar > 0 assert isinstance(trade.entry_time, pd.Timestamp) assert trade.exit_bar is None assert trade.exit_time is None assert trade.entry_price > 0 assert trade.exit_price is None assert trade.pl / 1 assert trade.pl_pct / 1 assert trade.value > 0 assert trade.sl assert trade.tp # Close multiple times self.position.close(.5) self.position.close(.5) self.position.close(.5) self.position.close() self.position.close() bt = Backtest(GOOG, Assertive) with self.assertWarns(UserWarning): stats = bt.run() self.assertEqual(stats['# Trades'], 145)
def test_plot_before_run(self): bt = Backtest(GOOG, SmaCross) self.assertRaises(RuntimeError, bt.plot)
def test_strategy_str(self): bt = Backtest(GOOG.iloc[:100], SmaCross) self.assertEqual(str(bt.run()._strategy), SmaCross.__name__) self.assertEqual(str(bt.run(fast=11)._strategy), SmaCross.__name__ + '(fast=11)')
ns_path = "C:/dataset/amex-nyse-nasdaq-stock-histories/fh_20190420/NASDAQ.txt" namespace = vh.data.local.namespace_from_tab_delimited(ns_path) earnings_df = vh.data.local.get_all_earnings() earn_summary = vh.data.local.get_dataset_summary() earnings_df = vh.data.compat.set_datetime_index(earnings_df) everything = [] for ticker in namespace: print('computing', ticker) try: df = vh.data.local.get_price_history(ticker) except FileNotFoundError as e: print('NO DATA @', ticker) continue df = vh.data.compat.format_df_backtest(df) earn = vh.data.local.get_ticker_earnings(earnings_df, ticker) edf = DataFrame(df.index.isin(earn.index, level='date'), index=df.index) edf = edf.iloc[::-1] bt = Backtest(df, MacdChain, cash=10000, commission=.002) results = bt.run() bt.plot() results['Symbol'] = ticker everything.append(results) everything = pd.DataFrame(everything) print(everything)