Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into 138-initial-backtes…
Browse files Browse the repository at this point in the history
…ting-infrastructure

# Conflicts:
#	investing_algorithm_framework/app/app.py
#	investing_algorithm_framework/dependency_container.py
#	investing_algorithm_framework/domain/__init__.py
#	investing_algorithm_framework/domain/models/__init__.py
#	investing_algorithm_framework/infrastructure/__init__.py
#	investing_algorithm_framework/services/__init__.py
#	investing_algorithm_framework/services/order_service.py
  • Loading branch information
MDUYN committed Nov 10, 2023
2 parents 38894da + 79c7200 commit 5da2c3a
Show file tree
Hide file tree
Showing 24 changed files with 264 additions and 255 deletions.
11 changes: 6 additions & 5 deletions examples/app.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import pathlib

from investing_algorithm_framework import create_app, PortfolioConfiguration, \
RESOURCE_DIRECTORY, TimeUnit, TradingDataType, TradingTimeFrame
RESOURCE_DIRECTORY, TimeUnit, TradingDataType, TradingTimeFrame, Algorithm
from datetime import datetime, timedelta

app = create_app({RESOURCE_DIRECTORY: pathlib.Path(__file__).parent.resolve()})
Expand All @@ -10,7 +10,8 @@
market="<your_market>",
api_key="<your_api_key>",
secret_key="<your_secret_key>",
trading_symbol="<your_trading_symbol>"
trading_symbol="<your_trading_symbol>",

)
)

Expand All @@ -24,7 +25,7 @@
symbols=["BTC/EUR"],
trading_time_frame_start_date=datetime.now() - timedelta(days=60),
)
def perform_strategy(algorithm, market_data):
def perform_strategy(algorithm: Algorithm, market_data):
print(algorithm.get_portfolio())
print(algorithm.get_positions())
print(algorithm.get_orders())
Expand All @@ -34,9 +35,9 @@ def perform_strategy(algorithm, market_data):
algorithm.close_position("<symbol>")
else:
algorithm.create_limit_order(
symbol="<symbol>",
target_symbol="<symbol>",
side="buy",
percentage_portfolio=20,
percentage_of_portfolio=20,
price=market_data["tickers"]["<symbol>"]["bid"]
)

Expand Down
25 changes: 15 additions & 10 deletions investing_algorithm_framework/app/algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from investing_algorithm_framework.domain import OrderStatus, OrderFee, \
Position, Order, Portfolio, OrderType, OrderSide, ApiException, \
parse_decimal_to_string, PositionCost
parse_decimal_to_string

logger = logging.getLogger("investing_algorithm_framework")

Expand All @@ -17,15 +17,13 @@ def __init__(
portfolio_configuration_service,
portfolio_service,
position_service,
position_cost_service,
order_service,
market_service,
market_data_service,
strategy_orchestrator_service,
):
self.portfolio_service = portfolio_service
self.position_service = position_service
self.position_cost_service = position_cost_service
self.order_service = order_service
self.market_service = market_service
self._config = None
Expand Down Expand Up @@ -100,11 +98,22 @@ def create_limit_order(
):
portfolio = self.portfolio_service.find({"market": market})

if percentage_of_portfolio is not None and OrderSide.BUY.equals(side):
if percentage_of_portfolio is not None:
if not OrderSide.BUY.equals(side):
raise ApiException(
"Percentage of portfolio is only supported for BUY orders."
)

size = float(portfolio.net_size) * (percentage_of_portfolio / 100)
amount = floor(size / price)
amount = size / price

elif percentage_of_position is not None:

if not OrderSide.SELL.equals(side):
raise ApiException(
"Percentage of position is only supported for SELL orders."
)

if percentage_of_position is not None and OrderSide.SELL.equals(side):
position = self.position_service.find(
{
"symbol": target_symbol,
Expand Down Expand Up @@ -563,9 +572,5 @@ def has_open_orders(self, target_symbol, identifier=None, market=None):
query_params["status"] = OrderStatus.OPEN.value
return self.order_service.exists(query_params)

def get_position_costs(self, symbol, market=None, identifier=None) -> List[PositionCost]:
position = self.get_position(symbol, market, identifier)
return self.position_cost_service.get_all({"position": position.id, "itemized": True})

def check_pending_orders(self):
self.order_service.check_pending_orders()
5 changes: 2 additions & 3 deletions investing_algorithm_framework/app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
from investing_algorithm_framework.app.web import create_flask_app
from investing_algorithm_framework.domain import DATABASE_NAME, TimeUnit, \
DATABASE_DIRECTORY_PATH, RESOURCE_DIRECTORY, ENVIRONMENT, Environment, \
SQLALCHEMY_DATABASE_URI, Config, OperationalException, \
PortfolioConfiguration
SQLALCHEMY_DATABASE_URI, Config, OperationalException, PortfolioConfiguration
from investing_algorithm_framework.infrastructure import setup_sqlalchemy, \
create_all_tables, MarketBacktestService
from investing_algorithm_framework.services import OrderBacktestService
Expand Down Expand Up @@ -463,7 +462,7 @@ def _create_database_if_not_exists(self):
raise OperationalException(
"Could not create database directory"
)

def get_portfolio_configurations(self):
return self.algorithm.get_portfolio_configurations()

Expand Down
15 changes: 3 additions & 12 deletions investing_algorithm_framework/dependency_container.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
from dependency_injector import containers, providers

from investing_algorithm_framework.app.algorithm import Algorithm
from investing_algorithm_framework.infrastructure import SQLOrderRepository, \
SQLPositionRepository, MarketService, SQLPortfolioRepository, \
SQLPositionCostRepository, SQLOrderFeeRepository
SQLOrderFeeRepository
from investing_algorithm_framework.services import OrderService, \
PositionService, PortfolioService, StrategyOrchestratorService, \
PortfolioConfigurationService, MarketDataService, PositionCostService, \
BackTestService
from investing_algorithm_framework.app.algorithm import Algorithm
PortfolioConfigurationService, MarketDataService, BackTestService


def setup_dependency_container(app, modules=None, packages=None):
Expand All @@ -22,7 +21,6 @@ class DependencyContainer(containers.DeclarativeContainer):
order_repository = providers.Factory(SQLOrderRepository)
order_fee_repository = providers.Factory(SQLOrderFeeRepository)
position_repository = providers.Factory(SQLPositionRepository)
position_cost_repository = providers.Factory(SQLPositionCostRepository)
portfolio_repository = providers.Factory(SQLPortfolioRepository)
market_service = providers.Factory(MarketService)
market_data_service = providers.Factory(
Expand All @@ -37,18 +35,13 @@ class DependencyContainer(containers.DeclarativeContainer):
)
order_service = providers.Factory(
OrderService,
position_cost_repository=position_cost_repository,
order_repository=order_repository,
order_fee_repository=order_fee_repository,
portfolio_repository=portfolio_repository,
position_repository=position_repository,
market_service=market_service,
portfolio_configuration_service=portfolio_configuration_service,
)
position_cost_service = providers.Factory(
PositionCostService,
repository=position_cost_repository
)
position_service = providers.Factory(
PositionService,
repository=position_repository,
Expand Down Expand Up @@ -80,6 +73,4 @@ class DependencyContainer(containers.DeclarativeContainer):
market_service=market_service,
strategy_orchestrator_service=strategy_orchestrator_service,
market_data_service=market_data_service,
position_cost_service=position_cost_service,
)

9 changes: 3 additions & 6 deletions investing_algorithm_framework/domain/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from .models import OrderStatus, OrderSide, OrderType, TimeInterval, \
TimeUnit, TimeFrame, TradingTimeFrame, TradingDataType, Ticker, \
OHLCV, OrderBook, PortfolioConfiguration, AssetPrice, Portfolio, \
Position, Order, PositionCost, OrderFee, BacktestProfile
Position, Order, OrderFee
from .exceptions import OperationalException, ApiException, \
PermissionDeniedApiException, ImproperlyConfigured
from .constants import ITEMIZE, ITEMIZED, PER_PAGE, PAGE, ENVIRONMENT, \
Expand All @@ -12,7 +12,7 @@
from .singleton import Singleton
from .utils import random_string, append_dict_as_row_to_csv, \
add_column_headers_to_csv, get_total_amount_of_rows, \
csv_to_list, StoppableThread, pretty_print_backtest
csv_to_list, StoppableThread
from .strategy import Strategy
from .stateless_actions import StatelessActions
from .decimal_parsing import parse_decimal_to_string, parse_string_to_decimal
Expand Down Expand Up @@ -61,10 +61,7 @@
"Strategy",
"DATETIME_FORMAT",
"StatelessActions",
"PositionCost",
"OrderFee",
"parse_decimal_to_string",
"parse_string_to_decimal",
"BacktestProfile",
"pretty_print_backtest"
"parse_string_to_decimal"
]
7 changes: 2 additions & 5 deletions investing_algorithm_framework/domain/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
from .trading_data_types import TradingDataType
from .trading_time_frame import TradingTimeFrame
from .portfolio import PortfolioConfiguration, Portfolio
from .position import Position, PositionCost
from .backtest_profile import BacktestProfile
from .position import Position

__all__ = [
"OrderStatus",
Expand All @@ -25,8 +24,6 @@
"PortfolioConfiguration",
"AssetPrice",
"Position",
"PositionCost",
"Portfolio",
"OrderFee",
"BacktestProfile"
"OrderFee"
]
33 changes: 25 additions & 8 deletions investing_algorithm_framework/domain/models/order/order.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def __init__(
updated_at=None,
trade_closed_at=None,
trade_closed_price=None,
trade_closed_amount=None,
external_id=None,
filled_amount=None,
remaining_amount=None,
Expand Down Expand Up @@ -65,6 +66,7 @@ def __init__(
self.net_gain = parse_decimal_to_string(net_gain)
self.trade_closed_at = trade_closed_at
self.trade_closed_price = trade_closed_price
self.trade_closed_amount = trade_closed_amount
self.created_at = created_at
self.updated_at = updated_at
self.filled_amount = parse_decimal_to_string(filled_amount)
Expand Down Expand Up @@ -129,6 +131,12 @@ def get_trade_closed_price(self):
def set_trade_closed_price(self, trade_closed_price):
self.trade_closed_price = trade_closed_price

def get_trade_closed_amount(self):
return parse_string_to_decimal(self.trade_closed_amount)

def set_trade_closed_amount(self, trade_closed_amount):
self.trade_closed_amount = trade_closed_amount

def get_created_at(self):
return self.created_at

Expand Down Expand Up @@ -218,26 +226,34 @@ def from_ccxt_order(ccxt_order):

def update(self, data):

if 'amount' in data:
if 'amount' in data and data['amount'] is not None:
amount = data.pop('amount')
self.amount = parse_decimal_to_string(amount)

if 'price' in data:
if 'price' in data and data['price'] is not None:
price = data.pop('price')
self.price = parse_decimal_to_string(price)

if 'filled' in data:
if 'filled' in data and data['filled'] is not None:
filled_amount = data.pop('filled')
self.filled_amount = parse_decimal_to_string(filled_amount)

if 'remaining' in data:
if 'remaining' in data and data['remaining'] is not None:
remaining_amount = data.pop('remaining')
self.remaining_amount = parse_decimal_to_string(remaining_amount)

if 'net_gain' in data:
if 'net_gain' in data and data['net_gain'] is not None:
net_gain = data.pop('net_gain')
self.net_gain = parse_decimal_to_string(net_gain)

if 'trade_closed_price' in data and data['trade_closed_price'] is not None:
trade_closed_price = data.pop('trade_closed_price')
self.trade_closed_price = parse_decimal_to_string(trade_closed_price)

if 'trade_closed_amount' in data and data['trade_closed_amount'] is not None:
trade_closed_amount = data.pop('trade_closed_amount')
self.trade_closed_amount = parse_decimal_to_string(trade_closed_amount)

super().update(data)

def __repr__(self):
Expand All @@ -249,8 +265,9 @@ def __repr__(self):

return self.repr(
id=id_value,
price=self.price,
amount=self.amount,
price=self.get_price(),
amount=self.get_amount(),
net_gain=self.get_net_gain(),
external_id=self.external_id,
status=self.status,
target_symbol=self.target_symbol,
Expand All @@ -259,5 +276,5 @@ def __repr__(self):
order_type=self.order_type,
filled_amount=self.get_filled(),
remaining_amount=self.get_remaining(),
cost=self.cost,
cost=self.get_cost(),
)
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from .position import Position
from .position_cost import PositionCost

__all__ = ["Position", "PositionCost"]
__all__ = ["Position"]
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ def __init__(
self,
symbol=None,
amount=0,
cost=0,
portfolio_id=None
):
self.symbol = symbol
self.amount = amount
self.cost = cost
self.portfolio_id = portfolio_id

def get_symbol(self):
Expand All @@ -24,6 +26,12 @@ def set_symbol(self, symbol):
def get_amount(self):
return parse_string_to_decimal(self.amount)

def get_cost(self):
return parse_string_to_decimal(self.cost)

def set_cost(self, cost):
self.cost = cost

def set_amount(self, amount):
self.amount = amount

Expand Down
10 changes: 3 additions & 7 deletions investing_algorithm_framework/infrastructure/__init__.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
from .repositories import SQLOrderRepository, SQLPositionRepository, \
SQLPortfolioRepository, SQLPositionCostRepository, SQLOrderFeeRepository
from .services import MarketService, MarketBacktestService
SQLPortfolioRepository, SQLOrderFeeRepository
from .services import MarketService
from .database import setup_sqlalchemy, Session, \
create_all_tables
from .models import SQLPortfolio, SQLOrder, SQLPosition, SQLOrderFee, \
SQLPositionCost
from .models import SQLPortfolio, SQLOrder, SQLPosition, SQLOrderFee

__all__ = [
"create_all_tables",
"SQLPositionRepository",
"SQLPortfolioRepository",
"SQLPositionCostRepository",
"SQLOrderRepository",
"SQLOrderFeeRepository",
"MarketService",
Expand All @@ -20,6 +18,4 @@
"SQLOrder",
"SQLOrderFee",
"SQLPosition",
"SQLPositionCost",
"MarketBacktestService"
]
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from .order import SQLOrder, SQLOrderFee
from .portfolio import SQLPortfolio
from .position import SQLPosition, SQLPositionCost
from .position import SQLPosition

__all__ = [
"SQLOrder", "SQLPosition", "SQLPortfolio", "SQLPositionCost", "SQLOrderFee"
"SQLOrder", "SQLPosition", "SQLPortfolio", "SQLOrderFee"
]
Loading

0 comments on commit 5da2c3a

Please sign in to comment.