stratanalyzer – Strategy analyzers

Strategy analyzers provide an extensible way to attach different calculations to strategy executions.

class pyalgotrade.stratanalyzer.StrategyAnalyzer

Bases: object

Base class for strategy analyzers.

Note

This is a base class and should not be used directly.

Returns

class pyalgotrade.stratanalyzer.returns.Returns(maxLen=None)

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.
getCumulativeReturns()

Returns a pyalgotrade.dataseries.DataSeries with the cumulative returns for each bar.

getReturns()

Returns a pyalgotrade.dataseries.DataSeries with the returns for each bar.

Sharpe Ratio

class pyalgotrade.stratanalyzer.sharpe.SharpeRatio(useDailyReturns=True)

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.
getSharpeRatio(riskFreeRate, annualized=True)

Returns the Sharpe ratio for the strategy execution. If the volatility is 0, 0 is returned.

Parameters:
  • riskFreeRate (int/float.) – The risk free rate per annum.
  • annualized (boolean.) – True if the sharpe ratio should be annualized.

DrawDown

class pyalgotrade.stratanalyzer.drawdown.DrawDown

Bases: pyalgotrade.stratanalyzer.StrategyAnalyzer

A pyalgotrade.stratanalyzer.StrategyAnalyzer that calculates max. drawdown and longest drawdown duration for the portfolio.

getLongestDrawDownDuration()

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.

getMaxDrawDown()

Returns the max. (deepest) drawdown.

Trades

class pyalgotrade.stratanalyzer.trades.Trades

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.
getCount()

Returns the total number of trades.

getProfitableCount()

Returns the number of profitable trades.

getUnprofitableCount()

Returns the number of unprofitable trades.

getEvenCount()

Returns the number of trades whose net profit was 0.

getAll()

Returns a numpy.array with the profits/losses for each trade.

getProfits()

Returns a numpy.array with the profits for each profitable trade.

getLosses()

Returns a numpy.array with the losses for each unprofitable trade.

getAllReturns()

Returns a numpy.array with the returns for each trade.

getPositiveReturns()

Returns a numpy.array with the positive returns for each trade.

getNegativeReturns()

Returns a numpy.array with the negative returns for each trade.

getCommissionsForAllTrades()

Returns a numpy.array with the commissions for each trade.

getCommissionsForProfitableTrades()

Returns a numpy.array with the commissions for each profitable trade.

getCommissionsForUnprofitableTrades()

Returns a numpy.array with the commissions for each unprofitable trade.

getCommissionsForEvenTrades()

Returns a numpy.array with the commissions for each trade whose net profit was 0.

Example

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 __future__ import print_function

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

from . import sma_crossover

# Load the bars. This file was manually downloaded from Yahoo Finance.
feed = yahoofeed.Feed()
feed.addBarsFromCSV("orcl", "orcl-2000-yahoofinance.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: $1295462.60
Cumulative returns: 29.55 %
Sharpe ratio: 0.70
Max. drawdown: 24.58 %
Longest drawdown duration: 277 days, 0:00:00

Total trades: 13
Avg. profit: $14391
Profits std. dev.: $127520
Max. profit: $420782
Min. profit: $-89317
Avg. return:  2 %
Returns std. dev.: 13 %
Max. return: 46 %
Min. return: -7 %

Profitable trades: 3
Avg. profit: $196972
Profits std. dev.: $158985
Max. profit: $420782
Min. profit: $66466
Avg. return: 21 %
Returns std. dev.: 18 %
Max. return: 46 %
Min. return:  6 %

Unprofitable trades: 10
Avg. loss: $-40383
Losses std. dev.: $23579
Max. loss: $-89317
Min. loss: $-4702
Avg. return: -3 %
Returns std. dev.:  2 %
Max. return: -0 %
Min. return: -7 %

Table Of Contents

Previous topic

strategy – Basic strategy classes

Next topic

plotter – Strategy plotter

This Page