Skip to main content

A multi currency, event driven backtester written in Python.

Project description

pxtrade

Build Status Coverage Status

A multi currency, event driven backtester written in Python.

Installation

pip install pxtrade

Examples

Notebooks are available to cover the main concepts and examples.

Assets and Portfolios

Before we can run a backtest we need to define the assets and portfolios involved.

from pxtrade.assets import reset, Cash, Stock, FxRate, Portfolio


reset()
aud = Cash("AUD")
usd = Cash("USD")
audusd = FxRate("AUDUSD")
spy = Stock("SPY")
portfolio = Portfolio("USD", code="Portfolio")  # a portfolio denominated in USD
benchmark = Portfolio("USD", code="Benchmark")

print(portfolio)

Portfolio('USD')

portfolio.transfer(usd, 1e6)  # start both with 1M USD
benchmark.transfer(usd, 1e6)

print(portfolio)

Portfolio('USD'): Cash('USD', 1.0, currency_code='USD'): 1,000,000

portfolio.value

1000000.0

Imposing portfolio constraints through compliance

Ideally there will be risk limits in place when running a backtest. Some concrete compliance rules are provided, but you can also define your own by inheriting from ComplianceRule.

from pxtrade.compliance import Compliance, UnitLimit


for port in [portfolio, benchmark]:
    port.compliance = Compliance().add_rule(
        UnitLimit(spy, 1000)
    )

Defining a portfolio broker

Different portfolios / strategies are likely to vary materially in broker charges. All portfolios have a default broker that executes trades at the last price with no charge (or slippage). Brokers have separate execution and charges strategies. You can use the classes available or define custom strategies by inheriting from AbstractExecution or AbstractCharges. Note that backtesting supports multiple currencies. The portfolio could be denominated in USD, for example, but broker charges defined in AUD terms.

from pxtrade.broker import (
    Broker, 
    FillAtLastWithSlippage,
    FixedRatePlusPercentage,
)


portfolio.broker = Broker(
    execution_strategy=FillAtLastWithSlippage(0),  # no slippage, just fill at last
    charges_strategy=FixedRatePlusPercentage(20, 0, currency_code="AUD")  # fixed charge of AUD 20 per trade.
)

Defining a trading strategy

All strategy classes must inherit from pxtrade.Strategy and implement a generate_trades method. Note that the trades returned can either be None, a trade instance or list or trades.

from pxtrade import Strategy, Trade 


class ExampleStrategy(Strategy):
    def generate_trades(self):
        trades = list()

        # get the portfolio trades first
        if spy.price < 330:
            trades.append(Trade(portfolio, spy, +100))

        trades.append(Trade(benchmark, spy, +1000))

        return trades

The backtest instance and trade history

A backtest takes a strategy instance as its argument. Any instances of History then record state through time as events are processed.

from pxtrade import Backtest, History


backtest = Backtest(ExampleStrategy())

history = History(
    portfolios=[portfolio, benchmark],
    backtest=backtest
)

Loading event data

Events can be loaded either from yahoo finance or from an existing data frame.

from datetime import date
from pxtrade.events.yahoo import load_yahoo_prices


start_date = date(2020, 6, 30)
end_date = date(2020, 9, 30)

load_yahoo_prices(
    [spy, audusd], backtest,
    start_date=start_date,
    end_date=end_date,
)

Running the backtest and collecting history

backtest.run()

df = history.get()
df.columns
Index(['AUD', 'AUDUSD', 'Benchmark', 'Benchmark_AUD', 'Benchmark_SPY',
       'Benchmark_USD', 'Portfolio', 'Portfolio_AUD', 'Portfolio_SPY',
       'Portfolio_USD', 'SPY', 'USD'],
      dtype='object')
import cufflinks as cf


columns = ["Portfolio_SPY", "Benchmark_SPY", "SPY"]
df[columns].iplot(
    secondary_y="SPY",
    title="Portfolio Holdings of SPY",
)

holdings

columns = ["Portfolio", "Benchmark"]
df[columns].iplot(
    title="Portfolio Value",
)

holdings


Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pxtrade-0.2.0.tar.gz (18.1 kB view details)

Uploaded Source

Built Distribution

pxtrade-0.2.0-py3-none-any.whl (25.7 kB view details)

Uploaded Python 3

File details

Details for the file pxtrade-0.2.0.tar.gz.

File metadata

  • Download URL: pxtrade-0.2.0.tar.gz
  • Upload date:
  • Size: 18.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/50.3.2 requests-toolbelt/0.9.1 tqdm/4.50.2 CPython/3.8.3

File hashes

Hashes for pxtrade-0.2.0.tar.gz
Algorithm Hash digest
SHA256 53588b760df9e304ee39e1f146461bec84a62f589fa0842d645f98f60ac22af9
MD5 fdd1b3eabfa4b2e9d6edbc9d38ade838
BLAKE2b-256 a63f3e4c4d2296a82d8a225c67273f110130d8f9517717074e19212a0158f49e

See more details on using hashes here.

File details

Details for the file pxtrade-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: pxtrade-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 25.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/50.3.2 requests-toolbelt/0.9.1 tqdm/4.50.2 CPython/3.8.3

File hashes

Hashes for pxtrade-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7f6e553d22a9c20f9b899e2353120a383745550bcb4e7d4179c0a2a751c550cd
MD5 d53016d595cb28fb70c99c955666b186
BLAKE2b-256 a44e8758ef3cd649bf60791ce4bb424b34dc3e989201bf4536ed6612a09c2e68

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page