Skip to content

Commit

Permalink
Fix sync orders on first load
Browse files Browse the repository at this point in the history
  • Loading branch information
MDUYN committed Mar 27, 2024
1 parent f99ab29 commit 67ec6e6
Show file tree
Hide file tree
Showing 23 changed files with 429 additions and 892 deletions.
24 changes: 17 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ from investing_algorithm_framework import create_app, PortfolioConfiguration, \
RESOURCE_DIRECTORY, TimeUnit, CCXTOHLCVMarketDataSource, Algorithm, \
CCXTTickerMarketDataSource, MarketCredential, SYMBOLS

# Define the symbols you want to trade for optimization, otherwise it will
# check all available symbols on the market
# Define the symbols you want to trade for optimization, otherwise the
# algorithm will check if you have orders and balances on all available
# symbols on the market
symbols = ["BTC/EUR"]

# Define resource directory and the symbols you want to trade
Expand Down Expand Up @@ -100,16 +101,25 @@ def perform_strategy(algorithm: Algorithm, market_data: dict):

# Ticker data is passed as {"<identifier>": <ticker dict>}
ticker_data = market_data["BTC-ticker"]
order = algorithm.create_limit_order(
unallocated_balance = algorithm.get_unallocated()
positions = algorithm.get_positions()
trades = algorithm.get_trades()
open_trades = algorithm.get_open_trades()
closed_trades = algorithm.get_closed_trades()

# Create a buy oder
algorithm.create_limit_order(
target_symbol="BTC/EUR",
order_side="buy",
amount=0.01,
price=ticker_data["ask"],
)
positions = algorithm.get_positions()
trades = algorithm.get_trades()
open_trades = algorithm.get_open_trades()
closed_trades = algorithm.get_closed_trades()

# Close a trade
algorithm.close_trade(trades[0].id)

# Close a position
algorithm.close_position(positions[0].get_symbol())

if __name__ == "__main__":
app.run()
Expand Down
29 changes: 25 additions & 4 deletions examples/backtest_experiment/algorithms/algorithm.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from investing_algorithm_framework import Algorithm, TradingStrategy, \
TimeUnit, OrderSide
TimeUnit, OrderSide, DATETIME_FORMAT
import tulipy as ti
import polars as pl


def is_below_trend(fast_series, slow_series):
return fast_series[-1] < slow_series[-1]
Expand Down Expand Up @@ -39,10 +41,11 @@ class Strategy(TradingStrategy):
]
symbols = ["BTC/EUR", "DOT/EUR"]

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

def apply_strategy(self, algorithm: Algorithm, market_data):
Expand Down Expand Up @@ -81,17 +84,35 @@ def apply_strategy(self, algorithm: Algorithm, market_data):
for trade in open_trades:
algorithm.close_trade(trade)

# Checking manual stop losses
open_trades = algorithm.get_open_trades(target_symbol)

for open_trade in open_trades:
filtered_df = df.filter(
pl.col('Datetime') >= open_trade.opened_at.strftime(DATETIME_FORMAT)
)
close_prices = filtered_df['Close'].to_numpy()
current_price = market_data[f"{symbol}-ticker"]

if open_trade.is_manual_stop_loss_trigger(
prices=close_prices,
current_price=current_price["bid"],
stop_loss_percentage=self.stop_loss_percentage
):
algorithm.close_trade(open_trade)


def create_algorithm(
name,
description,
fast,
slow,
trend
trend,
stop_loss_percentage
) -> Algorithm:
algorithm = Algorithm(
name=name,
description=description
)
algorithm.add_strategy(Strategy(fast, slow, trend))
algorithm.add_strategy(Strategy(fast, slow, trend, stop_loss_percentage))
return algorithm
54 changes: 36 additions & 18 deletions examples/backtest_experiment/backtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,126 +25,144 @@
description="9-50-100",
fast=9,
slow=50,
trend=100
trend=100,
stop_loss_percentage=7
),
create_algorithm(
name="10-50-100",
description="10-50-100",
fast=10,
slow=50,
trend=100
trend=100,
stop_loss_percentage=7
),
create_algorithm(
name="11-50-100",
description="11-50-100",
fast=11,
slow=50,
trend=100
trend=100,
stop_loss_percentage=7
),
create_algorithm(
name="9-75-150",
description="9-75-150",
fast=9,
slow=75,
trend=150
trend=150,
stop_loss_percentage=7
),
create_algorithm(
name="10-75-150",
description="10-75-150",
fast=10,
slow=75,
trend=150
trend=150,
stop_loss_percentage=7
),
create_algorithm(
name="11-75-150",
description="11-75-150",
fast=11,
slow=75,
trend=150
trend=150,
stop_loss_percentage=7
),
create_algorithm(
name="20-75-150",
description="20-75-150",
fast=20,
slow=75,
trend=150
trend=150,
stop_loss_percentage=7
),
create_algorithm(
name="21-75-150",
description="21-75-150",
fast=21,
slow=75,
trend=150
trend=150,
stop_loss_percentage=7
),
create_algorithm(
name="22-75-150",
description="22-75-150",
fast=22,
slow=75,
trend=150
trend=150,
stop_loss_percentage=7
),
create_algorithm(
name="23-75-150",
description="23-75-150",
fast=23,
slow=75,
trend=150
trend=150,
stop_loss_percentage=7
),
create_algorithm(
name="24-75-150",
description="24-75-150",
fast=24,
slow=75,
trend=150
trend=150,
stop_loss_percentage=7
),
create_algorithm(
name="25-75-150",
description="25-75-150",
fast=25,
slow=75,
trend=150
trend=150,
stop_loss_percentage=7
),
create_algorithm(
name="20-75-200",
description="20-75-200",
fast=20,
slow=75,
trend=200
trend=200,
stop_loss_percentage=7
),
create_algorithm(
name="21-75-200",
description="24-75-200",
fast=24,
slow=75,
trend=200
trend=200,
stop_loss_percentage=7
),
create_algorithm(
name="22-75-200",
description="24-75-200",
fast=24,
slow=75,
trend=200
trend=200,
stop_loss_percentage=7
),
create_algorithm(
name="23-75-200",
description="24-75-200",
fast=24,
slow=75,
trend=200
trend=200,
stop_loss_percentage=7
),
create_algorithm(
name="24-75-200",
description="24-75-200",
fast=24,
slow=75,
trend=200
trend=200,
stop_loss_percentage=7
),
create_algorithm(
name="25-75-150",
description="25-75-200",
fast=25,
slow=75,
trend=200
trend=200,
stop_loss_percentage=7
),
],
start_date=start_date,
Expand Down
5 changes: 3 additions & 2 deletions investing_algorithm_framework/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
Trade, OHLCVMarketDataSource, OrderBookMarketDataSource, SYMBOLS, \
TickerMarketDataSource, MarketService, BacktestReportsEvaluation, \
pretty_print_backtest_reports_evaluation, load_backtest_reports, \
RESERVED_BALANCES, APP_MODE, AppMode
RESERVED_BALANCES, APP_MODE, AppMode, DATETIME_FORMAT
from investing_algorithm_framework.app import TradingStrategy, \
StatelessAction, Task
from investing_algorithm_framework.infrastructure import \
Expand Down Expand Up @@ -59,5 +59,6 @@
"SYMBOLS",
"RESERVED_BALANCES",
"APP_MODE",
"AppMode"
"AppMode",
"DATETIME_FORMAT",
]
15 changes: 8 additions & 7 deletions investing_algorithm_framework/app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,13 @@ def initialize(self, sync=False):
trade_service=self.container.trade_service(),
)

if self._stateless:
self.config[APP_MODE] = AppMode.STATELESS.value
elif self._web:
self.config[APP_MODE] = AppMode.WEB.value
else:
self.config[APP_MODE] = AppMode.DEFAULT.value
if APP_MODE not in self.config:
if self._stateless:
self.config[APP_MODE] = AppMode.STATELESS.value
elif self._web:
self.config[APP_MODE] = AppMode.WEB.value
else:
self.config[APP_MODE] = AppMode.DEFAULT.value

if AppMode.WEB.from_value(self.config[APP_MODE]):
self._initialize_web()
Expand Down Expand Up @@ -460,7 +461,7 @@ def run(
for hook in self._on_after_initialize_hooks:
hook.on_run(self, self.algorithm)

self.initialize()
self.initialize(sync=sync)

# Run all on_initialize hooks
for hook in self._on_initialize_hooks:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import logging
from typing import Dict
from abc import ABC, abstractmethod
from datetime import datetime

from polars import DataFrame
logger = logging.getLogger("investing_algorithm_framework")


Expand Down Expand Up @@ -98,13 +99,13 @@ def get_closed_orders(
@abstractmethod
def get_ohlcv(
self, symbol, time_frame, from_timestamp, market, to_timestamp=None
):
) -> DataFrame:
raise NotImplementedError()

@abstractmethod
def get_ohlcvs(
self, symbols, time_frame, from_timestamp, market, to_timestamp=None
):
) -> Dict[str, DataFrame]:
raise NotImplementedError()

@property
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ def get_data(self, **kwargs):
first_row = df.head(1)[0]

if first_row["Datetime"][0] > end_date.strftime(DATETIME_FORMAT):
logger.warn(
logger.warning(
f"No ticker data available for the given backtest "
f"index date {backtest_index_date} and symbol {self.symbol} "
f"and market {self.market}"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import logging
from typing import Dict
from datetime import datetime
from time import sleep

import polars as pl
import ccxt
from dateutil import parser
from dateutil.tz import gettz
Expand Down Expand Up @@ -341,7 +342,7 @@ def get_closed_orders(

def get_ohlcv(
self, symbol, time_frame, from_timestamp, market, to_timestamp=None
):
) -> pl.DataFrame:
market_credential = self.get_market_credential(market)
exchange = self.initialize_exchange(market, market_credential)

Expand Down Expand Up @@ -388,7 +389,15 @@ def get_ohlcv(

sleep(exchange.rateLimit / 1000)

return data
# Predefined column names
col_names = ["Datetime", "Open", "High", "Low", "Close", "Volume"]

# Combine the Series into a DataFrame with given column names
df = pl.DataFrame(data)

# Assign column names after DataFrame creation
df.columns = col_names
return df

def get_ohlcvs(
self,
Expand All @@ -397,7 +406,7 @@ def get_ohlcvs(
from_timestamp,
market,
to_timestamp=None
):
) -> Dict[str, pl.DataFrame]:
ohlcvs = {}

for symbol in symbols:
Expand Down
Loading

0 comments on commit 67ec6e6

Please sign in to comment.