Skip to content

Commit

Permalink
Add experiment multiple algorithms support (#252)
Browse files Browse the repository at this point in the history
* Add experiment multiple algorithms support

* Add experimentation functionality

* Fix ohlcv data sources tests

* Fix ohlcv data sources tests
  • Loading branch information
MDUYN committed Mar 22, 2024
1 parent ca22899 commit be8d930
Show file tree
Hide file tree
Showing 145 changed files with 10,901 additions and 11,943 deletions.
160 changes: 64 additions & 96 deletions README.md

Large diffs are not rendered by default.

File renamed without changes.
File renamed without changes.
5 changes: 5 additions & 0 deletions examples/backtest/algorithm/algorithm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from investing_algorithm_framework import Algorithm
from .strategy import CrossOverStrategy

algorithm = Algorithm()
algorithm.add_strategy(CrossOverStrategy)
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
https://tulipindicators.org/ or go directly to the pypi page:
https://pypi.org/project/tulipy/
"""
# Define market data sources

def is_below_trend(fast_series, slow_series):
return fast_series[-1] < slow_series[-1]

Expand Down Expand Up @@ -55,6 +53,9 @@ class CrossOverStrategy(TradingStrategy):
"DOT/EUR-ticker"
]
symbols = ["BTC/EUR", "DOT/EUR"]
fast = 9
slow = 50
trend = 100

def apply_strategy(self, algorithm: Algorithm, market_data):

Expand All @@ -72,8 +73,8 @@ def apply_strategy(self, algorithm: Algorithm, market_data):
price = ticker_data['bid']

if not algorithm.has_position(target_symbol) \
and is_crossover(fast, slow)\
and not is_above_trend(fast, trend):
and is_crossover(fast, slow) \
and is_above_trend(fast, trend):
algorithm.create_limit_order(
target_symbol=target_symbol,
order_side=OrderSide.BUY,
Expand All @@ -84,6 +85,7 @@ def apply_strategy(self, algorithm: Algorithm, market_data):

if algorithm.has_position(target_symbol) \
and is_below_trend(fast, slow):

open_trades = algorithm.get_open_trades(
target_symbol=target_symbol
)
Expand Down
7 changes: 7 additions & 0 deletions examples/backtest/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import pathlib

from investing_algorithm_framework import create_app, RESOURCE_DIRECTORY

app = create_app(
config={RESOURCE_DIRECTORY: pathlib.Path(__file__).parent.resolve()}
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@
pretty_print_backtest

from app import app
from algorithm.algorithm import algorithm
from algorithm.data_sources import bitvavo_btc_eur_ohlcv_2h, \
bitvavo_dot_eur_ohlcv_2h, bitvavo_dot_eur_ticker, bitvavo_btc_eur_ticker


app.add_algorithm(algorithm)
app.add_market_data_source(bitvavo_btc_eur_ohlcv_2h)
app.add_market_data_source(bitvavo_dot_eur_ohlcv_2h)
app.add_market_data_source(bitvavo_btc_eur_ticker)
app.add_market_data_source(bitvavo_dot_eur_ticker)


# Add a portfolio configuration of 400 euro initial balance
Expand All @@ -18,10 +28,10 @@
if __name__ == "__main__":
end_date = datetime(2023, 12, 2)
start_date = end_date - timedelta(days=100)
experiment_report, backtest_reports = app.experiment(
backtest_report = app.run_backtest(
algorithm=algorithm,
start_date=start_date,
end_date=end_date,
pending_order_check_interval="2h",
strategies=[]
)
pretty_print_expirement(expirement_report)
pretty_print_backtest(backtest_report)
Empty file.
4 changes: 4 additions & 0 deletions examples/backtest_expirement/algorithms/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .algorithm import create_algorithm


__all__ = ["create_algorithm"]
97 changes: 97 additions & 0 deletions examples/backtest_expirement/algorithms/algorithm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
from investing_algorithm_framework import Algorithm, TradingStrategy, \
TimeUnit, OrderSide
import tulipy as ti

def is_below_trend(fast_series, slow_series):
return fast_series[-1] < slow_series[-1]


def is_above_trend(fast_series, slow_series):
return fast_series[-1] > slow_series[-1]


def is_crossover(fast, slow):
"""
Expect df to have columns: Date, ma_<period_one>, ma_<period_two>.
With the given date time it will check if the ma_<period_one> is a
crossover with the ma_<period_two>
"""
return fast[-2] <= slow[-2] and fast[-1] > slow[-1]


def is_crossunder(fast, slow):
"""
Expect df to have columns: Date, ma_<period_one>, ma_<period_two>.
With the given date time it will check if the ma_<period_one> is a
crossover with the ma_<period_two>
"""
return fast[-2] >= slow[-2] and fast[-1] < slow[-1]


class Strategy(TradingStrategy):
time_unit = TimeUnit.HOUR
interval = 2
market_data_sources = [
"BTC/EUR-ohlcv",
"DOT/EUR-ohlcv",
"BTC/EUR-ticker",
"DOT/EUR-ticker"
]
symbols = ["BTC/EUR", "DOT/EUR"]

def __init__(self, fast, slow, trend):
self.fast = fast
self.slow = slow
self.trend = trend
super().__init__()

def apply_strategy(self, algorithm: Algorithm, market_data):

for symbol in self.symbols:
target_symbol = symbol.split('/')[0]

if algorithm.has_open_orders(target_symbol):
continue

df = market_data[f"{symbol}-ohlcv"]
ticker_data = market_data[f"{symbol}-ticker"]
fast = ti.sma(df['Close'].to_numpy(), self.fast)
slow = ti.sma(df['Close'].to_numpy(), self.slow)
trend = ti.sma(df['Close'].to_numpy(), self.trend)
price = ticker_data['bid']

if not algorithm.has_position(target_symbol) \
and is_crossover(fast, slow) \
and is_above_trend(fast, trend):
algorithm.create_limit_order(
target_symbol=target_symbol,
order_side=OrderSide.BUY,
price=price,
percentage_of_portfolio=25,
precision=4,
)

if algorithm.has_position(target_symbol) \
and is_below_trend(fast, slow):

open_trades = algorithm.get_open_trades(
target_symbol=target_symbol
)

for trade in open_trades:
algorithm.close_trade(trade)


def create_algorithm(
name,
description,
fast,
slow,
trend
) -> Algorithm:
algorithm = Algorithm(
name=name,
description=description
)
algorithm.add_strategy(Strategy(fast, slow, trend))
return algorithm
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@
from data_sources import bitvavo_btc_eur_ohlcv_2h, bitvavo_dot_eur_ohlcv_2h, \
bitvavo_dot_eur_ticker, bitvavo_btc_eur_ticker
from investing_algorithm_framework import create_app, RESOURCE_DIRECTORY
from strategy import CrossOverStrategy

app = create_app(
config={RESOURCE_DIRECTORY: pathlib.Path(__file__).parent.resolve()}
)
app.add_strategy(CrossOverStrategy)
app.add_market_data_source(bitvavo_btc_eur_ohlcv_2h)
app.add_market_data_source(bitvavo_dot_eur_ohlcv_2h)
app.add_market_data_source(bitvavo_btc_eur_ticker)
Expand Down
162 changes: 162 additions & 0 deletions examples/backtest_expirement/backtest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
from datetime import datetime, timedelta

from algorithms import create_algorithm
from app import app
from investing_algorithm_framework import PortfolioConfiguration, \
pretty_print_backtest_reports_evaluation, BacktestReportsEvaluation, \
load_backtest_reports


if __name__ == "__main__":
end_date = datetime(2023, 12, 2)
start_date = end_date - timedelta(days=100)
# Add a portfolio configuration of 400 euro initial balance
app.add_portfolio_configuration(
PortfolioConfiguration(
market="BINANCE",
trading_symbol="EUR",
initial_balance=400,
)
)

# Run the backtest for each algorithm
reports = app.run_backtests(
algorithms=[
create_algorithm(
name="9-50-100",
description="9-50-100",
fast=9,
slow=50,
trend=100
),
create_algorithm(
name="10-50-100",
description="10-50-100",
fast=10,
slow=50,
trend=100
),
create_algorithm(
name="11-50-100",
description="11-50-100",
fast=11,
slow=50,
trend=100
),
create_algorithm(
name="9-75-150",
description="9-75-150",
fast=9,
slow=75,
trend=150
),
create_algorithm(
name="10-75-150",
description="10-75-150",
fast=10,
slow=75,
trend=150
),
create_algorithm(
name="11-75-150",
description="11-75-150",
fast=11,
slow=75,
trend=150
),
create_algorithm(
name="20-75-150",
description="20-75-150",
fast=20,
slow=75,
trend=150
),
create_algorithm(
name="21-75-150",
description="21-75-150",
fast=21,
slow=75,
trend=150
),
create_algorithm(
name="22-75-150",
description="22-75-150",
fast=22,
slow=75,
trend=150
),
create_algorithm(
name="23-75-150",
description="23-75-150",
fast=23,
slow=75,
trend=150
),
create_algorithm(
name="24-75-150",
description="24-75-150",
fast=24,
slow=75,
trend=150
),
create_algorithm(
name="25-75-150",
description="25-75-150",
fast=25,
slow=75,
trend=150
),
create_algorithm(
name="20-75-200",
description="20-75-200",
fast=20,
slow=75,
trend=200
),
create_algorithm(
name="21-75-200",
description="24-75-200",
fast=24,
slow=75,
trend=200
),
create_algorithm(
name="22-75-200",
description="24-75-200",
fast=24,
slow=75,
trend=200
),
create_algorithm(
name="23-75-200",
description="24-75-200",
fast=24,
slow=75,
trend=200
),
create_algorithm(
name="24-75-200",
description="24-75-200",
fast=24,
slow=75,
trend=200
),
create_algorithm(
name="25-75-150",
description="25-75-200",
fast=25,
slow=75,
trend=200
),
],
start_date=start_date,
end_date=end_date,
pending_order_check_interval="2h",
)
evaluation = BacktestReportsEvaluation(reports)
pretty_print_backtest_reports_evaluation(evaluation)
reports = load_backtest_reports(
"backtest_reports"
)
evaluation = BacktestReportsEvaluation(reports)
pretty_print_backtest_reports_evaluation(evaluation)
File renamed without changes.
Loading

0 comments on commit be8d930

Please sign in to comment.