Getting Started
===============
Coin-test is a backtesting library designed for cryptocurrency trading. It supports trading strategies across multiple currencies and advanced configurations of tests, including cron-based scheduled execution of strategies, synthetic data generation, slippage modeling, and trading fees.
View `example analysis HTML report `_
Quick Start
-----------
Coin-test runs on Python 3.10 or higher. Install the package via pip:
.. code-block::
pip3 install coin-test
To run a backtest, import the coin-test library. Then define your data source, strategy, and test settings to run the analysis.
.. code-block:: python
import datetime as dt
import coin_test
import pandas as pd
from coin_test.backtest import Portfolio, Strategy, MarketTradeRequest
from coin_test.data import BinanceDataset, FillProcessor, GarchDatasetGenerator
from coin_test.util import AssetPair, Money, Side
Then, define the assets to trade and your starting portfolio.
.. code-block:: python
# Define assets traded and an initial portfolio
eth, usdt = eth_usdt = AssetPair.from_str("ETH", "USDT")
portfolio = Portfolio(base_currency=usdt, assets={eth: Money(eth, 0), usdt: Money(usdt, 10000)})
Next, import daily historical data from Binance for the backtest and fill gaps.
.. code-block:: python
# Download the last 150 days of data
freq ='d'
dataset = BinanceDataset("ETH/USDT Daily Data", eth_usdt, freq=freq, start=dt.datetime.today()-dt.timedelta(days=150))
dataset.process([FillProcessor(freq)])
Now we wish to generate synthetic data to allow backtesting on a variety of future market conditions.
The existing data is split into a train/test split and then fed to a GARCH statistical model to generate new data.
.. code-block:: python
# Split the data into train test split
train, test = dataset.split(percent=0.75)
# Generate 30 synthetic datasets 90 days long and package them for backtesting
datasets = GarchDatasetGenerator(train).generate(timedelta=pd.Timedelta(days=90), n=30)
datasets = [[d] for d in datasets] # Package the datasets for backtesting
To implement a custom strategy, extend the ``Strategy`` class. Each strategy should have
* a schedule, which is a cron string representing when this strategy is run
* a lookback, which is how much data is accessed in the strategy
* a ``__call__`` method, which returns a list of TradeRequest objects representing trades the strategy wants to make.
A code example for implementing ``MACD_discrete_days`` strategy is shown below.
.. code-block:: python
class MACD_discrete_days(Strategy):
def __init__(self, asset_pair) -> None:
"""Initialize a MACD object.
This strategy uses a 26, 12, 9 standard EMACD calculation to generate buy sell signals.
Made to be used with Hour data"""
super().__init__(
name="MACD_Discrete_day",
asset_pairs=[asset_pair],
schedule="0 9 * * *",
lookback=dt.timedelta(days=26),
)
self.perc = .98
self.invested = False
def __call__(self, time, portfolio, lookback_data):
"""Execute strategy."""
asset_ticker, base_ticker = asset_pair = self.asset_pairs[0]
data = lookback_data[asset_pair]["Close"]
macd, signal, fast_ma, slow_ma = macd_indicator(data, 12, 26, 9)
if signal < macd and not self.invested:
self.invested =True
return [MarketTradeRequest(
asset_pair,
Side.BUY,
notional=portfolio.available_assets(base_ticker).qty * self.perc,
)]
elif signal > macd and self.invested:
self.invested = False
return [MarketTradeRequest(
asset_pair,
Side.SELL,
qty=portfolio.available_assets(asset_ticker).qty * self.perc,
)]
else:
return []
To run the backtest, create a portfolio with starting values of assets and call the ``run`` method. This package supports testing multiple strategies at once. See our `user guide in docs `_ for more advanced features and customization options.
.. code-block:: python
# Package the strategies before backtesting
strategies = [[MACD_discrete_days(eth_usdt)]]
# Run the backtest and generate the report
results = coin_test.run(datasets, strategies, portfolio, backtest_length=pd.Timedelta(days=90), n_parallel=8)
`Check out the report generated by this example! `_