def test_dividends_multiple_assets(self): start_date = date(1986, 12, 31) end_date = date(2019, 12, 31) msft_vals = self.msft_vals.reindex(pd.date_range(start_date, end_date)).ffill() msft_dividends = self.msft_dividends.reindex( pd.date_range(start_date, end_date) ).dropna() aapl_vals = self.aapl_vals.reindex(pd.date_range(start_date, end_date)).ffill() aapl_dividends = self.aapl_dividends.reindex( pd.date_range(start_date, end_date) ).dropna() assets = [ anda.Asset("MSFT", Decimal("0.5"), msft_vals, msft_dividends), anda.Asset("AAPL", Decimal("0.5"), aapl_vals, aapl_dividends), ] strategy = anda.Strategy( start_date, end_date, self.starting_balance, assets, self.contribution_dates, self.contribution_amount, self.rebalancing_dates, ) self.assertAlmostEqual( anda.total_return(strategy)[end_date], Decimal("9856511.60"), delta=1 )
def test_sortino_ratio_multi_asset(self): start_date = date(1989, 12, 29) end_date = date(2000, 12, 29) msft_vals = self.msft_vals.reindex(pd.date_range(start_date, end_date)).ffill() berkshire_vals = self.berkshire_vals.reindex( pd.date_range(start_date, end_date) ).ffill() risk_free_vals = ( self.risk_free_vals.dropna()["Close"] .reindex(pd.date_range(start_date, end_date)) .ffill() ) assets = [ anda.Asset("MSFT", Decimal(0.6), msft_vals), anda.Asset("BRK-A", Decimal(0.4), berkshire_vals), ] strategy = anda.Strategy( start_date, end_date, self.starting_balance, assets, self.contribution_dates, self.contribution_amount, self.rebalancing_dates, ) self.assertAlmostEqual( anda.sortino_ratio(strategy, risk_free_vals), Decimal("1.56"), delta=0.2 )
def test_mult_assets(self): starting_balance = Decimal("100.00") contribution_dates = set() contribution_amount = Decimal("0.0") rebalancing_dates = set() assets = [ anda.Asset("GOLD", Decimal("0.4"), self.gold_data), anda.Asset("SLV", Decimal("0.6"), self.silver_data), ] strategy = anda.Strategy( self.start, self.end, starting_balance, assets, contribution_dates, contribution_amount, rebalancing_dates, ) roi = anda.total_return(strategy) self.assertEqual(roi[self.start], Decimal("100.00")) self.assertEqual(roi[self.start + timedelta(days=14)], Decimal("220.40")) self.assertEqual(roi[self.end], Decimal("320.40"))
def get_assets(tickers, proportions, start_date, end_date): """ Gets data for each ticker and puts it in an anda.Asset. Returns a list of all assets. """ assert len(tickers) == len(proportions) data = util.get_data(tickers, start_date, end_date) data = data.rename(columns={ "AOpen": "Open", "AClose": "Close", "ALow": "Low", "AHigh": "High" }) if data.empty: # raise error return None assets = [] for tick, prop in zip(tickers, proportions): asset_data = data[(data.AssetTicker == tick)] only_market_data = asset_data[[ "ADate", "Open", "Close", "Low", "High" ]] only_market_data.index = only_market_data["ADate"] assets.append(anda.Asset(tick, prop, only_market_data)) return assets
def test_msft(self): start_date = date(1986, 3, 13) end_date = date(2019, 1, 1) msft_vals = self.msft_vals.reindex(pd.date_range(start_date, end_date)).ffill() msft_dividends = self.msft_dividends.reindex( pd.date_range(start_date, end_date) ).dropna() assets = [anda.Asset("MSFT", Decimal("1.0"), msft_vals, msft_dividends)] strategy = anda.Strategy( start_date, end_date, self.starting_balance, assets, self.contribution_dates, self.contribution_amount, self.rebalancing_dates, ) annual_returns = anda.relative_yearly_returns(strategy) expected = [ # (year, change) (1987, Decimal("125")), (1988, Decimal("-2")), (2000, Decimal("-63")), (2001, Decimal("53")), (2002, Decimal("-22")), (2003, Decimal("7")), (2017, Decimal("41")), (2018, Decimal("21")), ] for year, change in expected: self.assertAlmostEqual( annual_returns.at[date(year, 1, 1)], change, delta=Decimal("0.5") )
def test_short_time(self): start_date = date(1989, 1, 4) end_date = date(1989, 12, 31) self.msft_vals = self.msft_vals.reindex( pd.date_range(start_date, end_date) ).ffill() assets = [ anda.Asset("MSFT", Decimal("1.0"), self.msft_vals), ] strategy = anda.Strategy( start_date, end_date, self.starting_balance, assets, self.contribution_dates, self.contribution_amount, self.rebalancing_dates, ) self.assertRaises(anda.InsufficientTimeframe, lambda: anda.best_year(strategy)) self.assertRaises(anda.InsufficientTimeframe, lambda: anda.worst_year(strategy)) self.assertRaises( anda.InsufficientTimeframe, lambda: anda.best_year_no(strategy) ) self.assertRaises( anda.InsufficientTimeframe, lambda: anda.worst_year_no(strategy) )
def test_simple(self): start_date = date(1989, 1, 4) end_date = date(2010, 1, 1) self.msft_vals = self.msft_vals.reindex( pd.date_range(start_date, end_date) ).ffill() assets = [ anda.Asset("MSFT", Decimal("1.0"), self.msft_vals), ] strategy = anda.Strategy( start_date, end_date, self.starting_balance, assets, self.contribution_dates, self.contribution_amount, self.rebalancing_dates, ) b = anda.best_year(strategy) w = anda.worst_year(strategy) self.assertAlmostEqual(b, Decimal("120"), delta=2) self.assertAlmostEqual(w, Decimal("-63"), delta=2) self.assertAlmostEqual(b, Decimal("122"), delta=Decimal("0.5")) self.assertAlmostEqual(w, Decimal("-63"), delta=Decimal("0.5")) b_year = anda.best_year_no(strategy) w_year = anda.worst_year_no(strategy) self.assertEqual(b_year, 1991) self.assertEqual(w_year, 2000)
def test_sortino_ratio_single_asset(self): start_date = date(1986, 12, 31) end_date = date(2019, 12, 31) msft_vals = self.msft_vals.reindex(pd.date_range(start_date, end_date)).ffill() risk_free_vals = ( self.risk_free_vals.dropna()["Close"] .reindex(pd.date_range(start_date, end_date)) .ffill() ) assets = [anda.Asset("MSFT", Decimal(1.0), msft_vals)] strategy = anda.Strategy( start_date, end_date, self.starting_balance, assets, self.contribution_dates, self.contribution_amount, self.rebalancing_dates, ) self.assertAlmostEqual( anda.sortino_ratio(strategy, risk_free_vals), Decimal("1.34"), delta=0.1 )
def get_strategy( tickers, proportions, handles, start_date, end_date, input_money, contribution_amount, contribution_dates, rebalancing_dates, ): """ Initializes and returns strategy object """ weights = [p for p in proportions if p is not None] normalise(weights) # Separate user-supplied data from Thalia-known data. user_assets = [] thalia_tickers = [] thalia_weights = [] for ticker, weight, handle in zip(tickers, weights, handles): if handle is None: thalia_tickers.append(ticker) thalia_weights.append(weight) else: user_assets.append((ticker, weight, handle)) thalia_data = get_assets(thalia_tickers, thalia_weights, start_date, end_date) if thalia_data is None: # raise error return None user_supplied_data = [ anda.Asset(ticker, weight, user_csv.retrieve(handle)) for ticker, weight, handle in user_assets ] all_asset_data = user_supplied_data + thalia_data real_start_date = max(asset.values.index[0] for asset in all_asset_data) real_end_date = min(asset.values.index[-1] for asset in all_asset_data) if real_end_date < real_start_date: # raise error return None strategy = anda.Strategy( real_start_date, real_end_date, input_money, all_asset_data, contribution_dates, contribution_amount, rebalancing_dates, ) return strategy
def test_max_drawdown_multi_asset(self): start_date = date(1989, 12, 29) end_date = date(2000, 12, 29) msft_vals = self.msft_vals.reindex(pd.date_range(start_date, end_date)).ffill() berkshire_vals = self.berkshire_vals.reindex( pd.date_range(start_date, end_date) ).ffill() assets = [ anda.Asset("MSFT", Decimal(0.6), msft_vals), anda.Asset("BRK-A", Decimal(0.4), berkshire_vals), ] strategy = anda.Strategy( start_date, end_date, self.starting_balance, assets, self.contribution_dates, self.contribution_amount, self.rebalancing_dates, ) self.assertAlmostEqual(anda.max_drawdown(strategy), Decimal("59.03"), delta=3)
def test_rebalancing(self): # TODO starting_balance = Decimal("10000.00") contribution_dates = set() contribution_amount = Decimal("0.0") rebalancing_dates = self.dates assets = [ anda.Asset("GOLD", Decimal("0.5"), self.gold_data), anda.Asset("SLV", Decimal("0.5"), self.silver_data), ] strategy = anda.Strategy( self.start, self.end, starting_balance, assets, contribution_dates, contribution_amount, rebalancing_dates, ) roi = anda.total_return(strategy) roi # gotta keep flake8 happy.
def test_max_drawdown_single_asset(self): start_date = date(1986, 12, 31) end_date = date(2019, 12, 31) msft_vals = self.msft_vals.reindex(pd.date_range(start_date, end_date)).ffill() assets = [anda.Asset("MSFT", Decimal("1.0"), msft_vals)] strategy = anda.Strategy( start_date, end_date, self.starting_balance, assets, self.contribution_dates, self.contribution_amount, self.rebalancing_dates, ) self.assertAlmostEqual(anda.max_drawdown(strategy), Decimal("72.33"), delta=2.5)
def test_single_asset(self): starting_balance = Decimal("23.46") contribution_dates = set() contribution_amount = None rebalancing_dates = set() assets = [anda.Asset("Gold", Decimal("1.0"), self.gold_data)] strategy = anda.Strategy( self.start, self.end, starting_balance, assets, contribution_dates, contribution_amount, rebalancing_dates, ) roi = anda.total_return(strategy) self.assertEqual(roi.at[self.start], Decimal("23.46")) self.assertEqual(roi.at[date(2000, 1, 12)], Decimal("24.75")) self.assertEqual(roi.at[self.end], Decimal("25.69"))
def test_no_money(self): starting_balance = Decimal("0.00") contribution_dates = pd.date_range( self.start, self.end, freq=timedelta(days=4) )[1:] contribution_amount = Decimal("1000.00") rebalancing_dates = set() assets = [anda.Asset("ST", Decimal("1.0"), self.rock_data)] strategy = anda.Strategy( self.start, self.end, starting_balance, assets, contribution_dates, contribution_amount, rebalancing_dates, ) roi = anda.total_return(strategy) roi # Just the lack of exception *should* be a sign of success.
def test_contribution(self): starting_balance = Decimal("1.00") contribution_dates = self.dates contribution_amount = Decimal("1.00") rebalancing_dates = set() assets = [anda.Asset("ST", Decimal("1.00"), self.rock_data)] strategy = anda.Strategy( self.start, self.end, starting_balance, assets, contribution_dates, contribution_amount, rebalancing_dates, ) roi = anda.total_return(strategy) self.assertEqual(Decimal("2.00"), roi.at[self.start]) for (day, next_day) in zip(self.dates, self.dates[1:]): self.assertEqual(roi[day] + Decimal("1.00"), roi[next_day])
def test_dividends_single_asset(self): start_date = date(1986, 12, 31) end_date = date(2019, 12, 31) msft_vals = self.msft_vals.reindex(pd.date_range(start_date, end_date)).ffill() msft_dividends = self.msft_dividends.reindex( pd.date_range(start_date, end_date) ).dropna() assets = [anda.Asset("MSFT", Decimal("1.0"), msft_vals, msft_dividends)] strategy = anda.Strategy( start_date, end_date, self.starting_balance, assets, self.contribution_dates, self.contribution_amount, self.rebalancing_dates, ) self.assertAlmostEqual( anda.total_return(strategy)[end_date], Decimal("14599199.22"), delta=1 )