Strategy analyzers provide an extensible way to attach different calculations to strategy executions.
Bases: object
Base class for strategy analyzers.
Note
This is a base class and should not be used directly.
Bases: pyalgotrade.stratanalyzer.StrategyAnalyzer
A pyalgotrade.stratanalyzer.StrategyAnalyzer that calculates time-weighted returns for the whole portfolio.
Parameters: | maxLen (int.) – The maximum number of values to hold in net and cumulative returs dataseries. Once a bounded length is full, when new items are added, a corresponding number of items are discarded from the opposite end. If None then dataseries.DEFAULT_MAX_LEN is used. |
---|
Returns a pyalgotrade.dataseries.DataSeries with the cumulative returns for each bar.
Returns a pyalgotrade.dataseries.DataSeries with the returns for each bar.
Bases: pyalgotrade.stratanalyzer.StrategyAnalyzer
A pyalgotrade.stratanalyzer.StrategyAnalyzer that calculates Sharpe ratio for the whole portfolio.
Parameters: | useDailyReturns (boolean.) – True if daily returns should be used instead of the returns for each bar. |
---|
Returns the Sharpe ratio for the strategy execution. If the volatility is 0, 0 is returned.
Parameters: |
|
---|
Bases: pyalgotrade.stratanalyzer.StrategyAnalyzer
A pyalgotrade.stratanalyzer.StrategyAnalyzer that calculates max. drawdown and longest drawdown duration for the portfolio.
Returns the duration of the longest drawdown.
Return type: | datetime.timedelta. |
---|
Note
Note that this is the duration of the longest drawdown, not necessarily the deepest one.
Returns the max. (deepest) drawdown.
Bases: pyalgotrade.stratanalyzer.StrategyAnalyzer
A pyalgotrade.stratanalyzer.StrategyAnalyzer that records the profit/loss and returns of every completed trade.
Note
This analyzer operates on individual completed trades. For example, lets say you start with a $1000 cash, and then you buy 1 share of XYZ for $10 and later sell it for $20:
- The trade’s profit was $10.
- The trade’s return is 100%, even though your whole portfolio went from $1000 to $1020, a 2% return.
Returns the total number of trades.
Returns the number of profitable trades.
Returns the number of unprofitable trades.
Returns the number of trades whose net profit was 0.
Returns a numpy.array with the profits/losses for each trade.
Returns a numpy.array with the profits for each profitable trade.
Returns a numpy.array with the losses for each unprofitable trade.
Returns a numpy.array with the returns for each trade.
Returns a numpy.array with the positive returns for each trade.
Returns a numpy.array with the negative returns for each trade.
Returns a numpy.array with the commissions for each trade.
Returns a numpy.array with the commissions for each profitable trade.
Returns a numpy.array with the commissions for each unprofitable trade.
Returns a numpy.array with the commissions for each trade whose net profit was 0.
Save this code as sma_crossover.py:
from pyalgotrade import strategy
from pyalgotrade.technical import ma
from pyalgotrade.technical import cross
class SMACrossOver(strategy.BacktestingStrategy):
def __init__(self, feed, instrument, smaPeriod):
super(SMACrossOver, self).__init__(feed)
self.__instrument = instrument
self.__position = None
# We'll use adjusted close values instead of regular close values.
self.setUseAdjustedValues(True)
self.__prices = feed[instrument].getPriceDataSeries()
self.__sma = ma.SMA(self.__prices, smaPeriod)
def getSMA(self):
return self.__sma
def onEnterCanceled(self, position):
self.__position = None
def onExitOk(self, position):
self.__position = None
def onExitCanceled(self, position):
# If the exit was canceled, re-submit it.
self.__position.exitMarket()
def onBars(self, bars):
# If a position was not opened, check if we should enter a long position.
if self.__position is None:
if cross.cross_above(self.__prices, self.__sma) > 0:
shares = int(self.getBroker().getCash() * 0.9 / bars[self.__instrument].getPrice())
# Enter a buy market order. The order is good till canceled.
self.__position = self.enterLong(self.__instrument, shares, True)
# Check if we have to exit the position.
elif not self.__position.exitActive() and cross.cross_below(self.__prices, self.__sma) > 0:
self.__position.exitMarket()
and save this code in a different file:
from pyalgotrade.barfeed import yahoofeed
from pyalgotrade.stratanalyzer import returns
from pyalgotrade.stratanalyzer import sharpe
from pyalgotrade.stratanalyzer import drawdown
from pyalgotrade.stratanalyzer import trades
import sma_crossover
# Load the yahoo feed from the CSV file
feed = yahoofeed.Feed()
feed.addBarsFromCSV("orcl", "orcl-2000.csv")
# Evaluate the strategy with the feed's bars.
myStrategy = sma_crossover.SMACrossOver(feed, "orcl", 20)
# Attach different analyzers to a strategy before executing it.
retAnalyzer = returns.Returns()
myStrategy.attachAnalyzer(retAnalyzer)
sharpeRatioAnalyzer = sharpe.SharpeRatio()
myStrategy.attachAnalyzer(sharpeRatioAnalyzer)
drawDownAnalyzer = drawdown.DrawDown()
myStrategy.attachAnalyzer(drawDownAnalyzer)
tradesAnalyzer = trades.Trades()
myStrategy.attachAnalyzer(tradesAnalyzer)
# Run the strategy.
myStrategy.run()
print "Final portfolio value: $%.2f" % myStrategy.getResult()
print "Cumulative returns: %.2f %%" % (retAnalyzer.getCumulativeReturns()[-1] * 100)
print "Sharpe ratio: %.2f" % (sharpeRatioAnalyzer.getSharpeRatio(0.05))
print "Max. drawdown: %.2f %%" % (drawDownAnalyzer.getMaxDrawDown() * 100)
print "Longest drawdown duration: %s" % (drawDownAnalyzer.getLongestDrawDownDuration())
print
print "Total trades: %d" % (tradesAnalyzer.getCount())
if tradesAnalyzer.getCount() > 0:
profits = tradesAnalyzer.getAll()
print "Avg. profit: $%2.f" % (profits.mean())
print "Profits std. dev.: $%2.f" % (profits.std())
print "Max. profit: $%2.f" % (profits.max())
print "Min. profit: $%2.f" % (profits.min())
returns = tradesAnalyzer.getAllReturns()
print "Avg. return: %2.f %%" % (returns.mean() * 100)
print "Returns std. dev.: %2.f %%" % (returns.std() * 100)
print "Max. return: %2.f %%" % (returns.max() * 100)
print "Min. return: %2.f %%" % (returns.min() * 100)
print
print "Profitable trades: %d" % (tradesAnalyzer.getProfitableCount())
if tradesAnalyzer.getProfitableCount() > 0:
profits = tradesAnalyzer.getProfits()
print "Avg. profit: $%2.f" % (profits.mean())
print "Profits std. dev.: $%2.f" % (profits.std())
print "Max. profit: $%2.f" % (profits.max())
print "Min. profit: $%2.f" % (profits.min())
returns = tradesAnalyzer.getPositiveReturns()
print "Avg. return: %2.f %%" % (returns.mean() * 100)
print "Returns std. dev.: %2.f %%" % (returns.std() * 100)
print "Max. return: %2.f %%" % (returns.max() * 100)
print "Min. return: %2.f %%" % (returns.min() * 100)
print
print "Unprofitable trades: %d" % (tradesAnalyzer.getUnprofitableCount())
if tradesAnalyzer.getUnprofitableCount() > 0:
losses = tradesAnalyzer.getLosses()
print "Avg. loss: $%2.f" % (losses.mean())
print "Losses std. dev.: $%2.f" % (losses.std())
print "Max. loss: $%2.f" % (losses.min())
print "Min. loss: $%2.f" % (losses.max())
returns = tradesAnalyzer.getNegativeReturns()
print "Avg. return: %2.f %%" % (returns.mean() * 100)
print "Returns std. dev.: %2.f %%" % (returns.std() * 100)
print "Max. return: %2.f %%" % (returns.max() * 100)
print "Min. return: %2.f %%" % (returns.min() * 100)
The output should look like this:
Final portfolio value: $1295887.22
Cumulative returns: 29.59 %
Sharpe ratio: 0.70
Max. drawdown: 24.53 %
Longest drawdown duration: 277 days, 0:00:00
Total trades: 13
Avg. profit: $14437
Profits std. dev.: $127539
Max. profit: $420866
Min. profit: $-89320
Avg. return: 2 %
Returns std. dev.: 13 %
Max. return: 46 %
Min. return: -7 %
Profitable trades: 3
Avg. profit: $197053
Profits std. dev.: $158987
Max. profit: $420866
Min. profit: $66537
Avg. return: 21 %
Returns std. dev.: 18 %
Max. return: 46 %
Min. return: 6 %
Unprofitable trades: 10
Avg. loss: $-40348
Losses std. dev.: $23601
Max. loss: $-89320
Min. loss: $-4516
Avg. return: -3 %
Returns std. dev.: 2 %
Max. return: -0 %
Min. return: -7 %