def test_decimals(self): # Long with decimals a = Account(2) a.EnterPosition('Long', 1, 0.00000001) self.assertEqual(a.TotalValue(0.00000002), 3) a.ClosePosition(a.Positions[0], 1, 0.00000002) self.assertEqual(a.BuyingPower, 3) #Short with decimals a = Account(2) a.EnterPosition('Short', 1, 0.00000002) self.assertEqual(a.TotalValue(0.00000001), 2.5) a.ClosePosition(a.Positions[0], 1, 0.00000001) self.assertEqual(a.BuyingPower, 2.5)
def test_both(self): a = Account(1000) a.EnterPosition('Long', 200, 20) a.EnterPosition('Short', 250, 25) self.assertEqual(a.BuyingPower, 550) self.assertEqual(a.TotalValue(25), 1050) Long = a.Positions[0] Short = a.Positions[1] a.ClosePosition(Long, 0.5, 40) a.ClosePosition(Short, 0.5, 12.5) self.assertEqual(a.BuyingPower, 937.5) self.assertEqual(a.TotalValue(12.5), 1187.5) a.ClosePosition(Long, 1.0, 50) a.ClosePosition(Short, 1.0, 50) self.assertEqual(a.BuyingPower, 1187.5) self.assertEqual(a.TotalValue(100), 1187.5)
def test_long(self): a = Account(1000) # Win on a long a.EnterPosition('Long', 500, 10) a.EnterPosition('Long', 500, 10) self.assertEqual(a.BuyingPower, 0) self.assertEqual(a.TotalValue(10), 1000) L0 = a.Positions[0] L1 = a.Positions[1] a.ClosePosition(L0, 0.5, 20) a.ClosePosition(L1, 0.5, 20) self.assertEqual(a.BuyingPower, 1000) self.assertEqual(a.TotalValue(20), 2000) a.ClosePosition(L0, 0.5, 40) a.ClosePosition(L1, 0.5, 40) self.assertEqual(a.BuyingPower, 2000) self.assertEqual(a.TotalValue(40), 3000) # Lose on a long a.EnterPosition('Long', 1000, 50) L2 = a.Positions[2] a.ClosePosition(L2, 0.5, 25) self.assertEqual(a.BuyingPower, 1250) self.assertEqual(a.TotalValue(25), 2125)
def test_short(self): a = Account(1000) # Win on a short a.EnterPosition('Short', 500, 10) a.EnterPosition('Short', 500, 10) self.assertEqual(a.BuyingPower, 0) self.assertEqual(a.TotalValue(10), 1000) S0 = a.Positions[0] S1 = a.Positions[1] a.ClosePosition(S0, 0.5, 5) a.ClosePosition(S1, 0.5, 5) self.assertEqual(a.BuyingPower, 750) self.assertEqual(a.TotalValue(5), 1500) a.ClosePosition(S0, 0.5, 2.5) a.ClosePosition(S1, 0.5, 2.5) self.assertEqual(a.BuyingPower, 1187.5) self.assertEqual(a.TotalValue(2.5), 1625) # Lose on a short a.EnterPosition('Short', 1000, 2) S2 = a.Positions[2] a.ClosePosition(S2, 0.5, 4) self.assertEqual(a.BuyingPower, 187.5) self.assertEqual(a.TotalValue(4), 587.5)
class Run(): def __init__(self, Data): self.Data = Data self.Data['date'] = pd.to_datetime(self.Data['date']) def Start(self, InitialCapital, Logic, Lookback=1, Start=False, End=False): # Initialize account self.Account = Account(InitialCapital) # Adjust custom timeframe if not (Start): Start = self.Data['date'].iloc[0] if not (End): End = self.Data['date'].iloc[-1] self.Start, self.End = Start, End self.Timeframe = self.Data.loc[(self.Data['date'] >= Start) & (self.Data['date'] <= End)] # Enter backtest --------------------------------------------- for Index, Today in self.Timeframe.iterrows(): Days = [self.Data.loc[Index]] for Day in range(Lookback): try: Days.insert(1, self.Data.loc[Index - Day - 1]) except KeyError: pass try: Days.insert(1, self.Data.loc[Index + 1]) except KeyError: pass # Update account variables self.Account.Date = Today['date'] self.Account.Equity.append(self.Account.TotalValue(Today['open'])) # Execute trading logic Logic(self.Account, Period(Days)) # Cleanup empty positions self.Account.PurgePositions() # ------------------------------------------------------------ def Results(self): print("-------------- Results ----------------\n") print("Period : %s...%s" % (self.Start, self.End)) BeginPrice = self.Timeframe.iloc[0]['open'] FinalPrice = self.Timeframe.iloc[-1]['close'] percentchange = PercentChange(BeginPrice, FinalPrice) print("Buy and Hold : %s%%" % round(percentchange * 100, 2)) print("Net Profit : %s " % round(Profit(self.Account.InitialCapital, percentchange), 2)) percentchange = PercentChange(self.Account.InitialCapital, self.Account.TotalValue(FinalPrice)) print("Strategy : %s%%" % round(percentchange * 100, 2)) print("Net Profit : %s " % round(Profit(self.Account.InitialCapital, percentchange), 2)) print("\n---------------------------------------") def AdvancedResults(self): print("-----------Advanced Results------------\n") Longs = len([T for T in self.Account.OpenedTrades if T.Type == 'Long']) Sells = len([T for T in self.Account.ClosedTrades if T.Type == 'Long']) Shorts = len( [T for T in self.Account.OpenedTrades if T.Type == 'Short']) Covers = len( [T for T in self.Account.ClosedTrades if T.Type == 'Short']) print("Longs : %s" % Longs) print("Sells : %s" % Sells) print("Shorts : %s" % Shorts) print("Covers : %s" % Covers) print("--------------------") print("Total Trades : %s" % (Longs + Sells + Shorts + Covers)) LongPerformances = [ PercentChange(T.Entry, T.Exit) for T in self.Account.ClosedTrades if T.Type == 'Long' ] ShortPerformances = [ -1 * PercentChange(T.Entry, T.Exit) for T in self.Account.ClosedTrades if T.Type == 'Short' ] print("\nLong/Short Performance\n----------------------------") print("Long (Worst) : %s%%" % round(min(LongPerformances) * 100, 2)) print("Long (Average) : %s%%" % round( (sum(LongPerformances) / len(LongPerformances)) * 100, 2)) print("Long (Best) : %s%%\n" % round(max(LongPerformances) * 100, 2)) print("Short (Worst) : %s%%" % round(min(ShortPerformances) * 100, 2)) print("Short (Average) : %s%%" % round( (sum(ShortPerformances) / len(ShortPerformances)) * 100, 2)) print("Short (Best) : %s%%" % round(max(ShortPerformances) * 100, 2)) Gains = [T for T in LongPerformances + ShortPerformances if T > 0] Losses = [T for T in LongPerformances + ShortPerformances if T < 0] print("\nGains/Losses\n-----------------------------") print("Gain (Largest) : %s%%" % round(max(Gains) * 100, 2)) print("Gain (Average) : %s%%" % round( (sum(Gains) / len(Gains)) * 100, 2)) print("Gain (Smallest) : %s%%" % round(min(Gains) * 100, 2)) print("Total Gains : %s\n" % (len(Gains))) print("Loss (Smallest) : %s%%" % round(max(Losses) * 100, 2)) print("Loss (Average) : %s%%" % round( (sum(Losses) / len(Losses)) * 100, 2)) print("Loss (Largest) : %s%%" % round(min(Losses) * 100, 2)) print("Total Losses : %s" % (len(Losses))) print("\n---------------------------------------") def Chart(self, ShowTrades=False): output_file("chart.html", title="Equity Curve") p = figure(x_axis_type="datetime", title="Equity Curve") p.legend.location = "top_left" p.grid.grid_line_alpha = 0.3 p.xaxis.axis_label = 'Date' p.yaxis.axis_label = 'Equity' Shares = self.Account.InitialCapital / self.Timeframe.iloc[0]['open'] BaseEquity = [Price * Shares for Price in self.Timeframe['open']] p.line(self.Timeframe['date'], BaseEquity, color='#CAD8DE', legend='Buy and Hold') p.line(self.Timeframe['date'], self.Account.Equity, color='#49516F', legend='Strategy') if ShowTrades: for Trade in self.Account.OpenedTrades: x = time.mktime(Trade.Date.timetuple()) * 1000 y = self.Account.Equity[np.where( self.Timeframe['date'] == Trade.Date.strftime("%Y-%m-%d")) [0][0]] if Trade.Type == 'Long': p.circle(x, y, size=6, color='green', alpha=0.5) elif Trade.Type == 'Short': p.circle(x, y, size=6, color='red', alpha=0.5) for Trade in self.Account.ClosedTrades: print(Trade.Type) x = time.mktime(Trade.Date.timetuple()) * 1000 y = self.Account.Equity[np.where( self.Timeframe['date'] == Trade.Date.strftime("%Y-%m-%d")) [0][0]] if Trade.Type == 'Long': p.circle(x, y, size=6, color='blue', alpha=0.5) elif Trade.Type == 'Short': p.circle(x, y, size=6, color='orange', alpha=0.5) show(p)