Skip to content

Commit

Permalink
Merge pull request #151 from AsyncAlgoTrading/exchanges
Browse files Browse the repository at this point in the history
Exchanges and strategies cleanup
  • Loading branch information
timkpaine committed Feb 1, 2021
2 parents 3186bd6 + 0e5f342 commit a61ff9a
Show file tree
Hide file tree
Showing 49 changed files with 466 additions and 343 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:

- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel twine numpy pyarrow>=1. cpplint
python -m pip install --upgrade pip setuptools wheel twine numpy pyarrow>=1. cpplint pyEX tqdm
python -m pip install -e .[dev]
cd js; yarn
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:

- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel twine numpy pyarrow>=1. cpplint
python -m pip install --upgrade pip setuptools wheel twine numpy pyarrow>=1. cpplint pyEX tqdm
python -m pip install -e .[dev]
cd js; yarn
Expand Down
46 changes: 12 additions & 34 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,6 @@ CONFIG=./config/synthetic.cfg
run: ## Clean and make target, run target
$(PYTHON) -m aat --config $(CONFIG)

iex: ## Clean and make target, run target
$(PYTHON) -m aat --config ./config/iex.cfg

iexintraday: ## Clean and make target, run target
$(PYTHON) -m aat --config ./config/iex_intraday.cfg

iexpintraday: ## Clean and make target, run target
$(PYTHON) -m aat --config ./private_config/iex_intraday.cfg

iexmomentum: ## Clean and make target, run target
$(PYTHON) -m aat --config ./config/iex_intraday_momentum.cfg

iexpmomentum: ## Clean and make target, run target
$(PYTHON) -m aat --config ./private_config/iex_intraday_momentum.cfg

iexlive: ## Clean and make target, run target
$(PYTHON) -m aat --config ./config/iex_live.cfg

ib: ## Clean and make target, run target
$(PYTHON) -m aat --config ./config/ib.cfg

ibpositions: ## Clean and make target, run target
$(PYTHON) -m aat --config ./config/ib_positions.cfg

coinbase: ## Clean and make target, run target
$(PYTHON) -m aat --config ./config/coinbase.cfg

coinbasesandbox: ## Clean and make target, run target
$(PYTHON) -m aat --config ./config/coinbase_sandbox.cfg

runcpp: build ## Clean and make target, run target
AAT_USE_CPP=1 $(PYTHON) -m aat --config $(CONFIG)

Expand Down Expand Up @@ -74,10 +44,18 @@ testpycpp: ## Make unit tests
testjs: ## Make js tests
cd js; yarn test

testruns: ## Run a few examples as a live end-to-end test
$(PYTHON) -m aat.strategy.sample.readonly
$(PYTHON) -m aat.strategy.sample.readonly_periodic
$(PYTHON) -m aat.strategy.sample.csv_received
testruns: testrunscsv testrunsiex ## Run a few examples as a live end-to-end test

testrunscsv:
$(PYTHON) -m aat.strategy.sample.csv.readonly
$(PYTHON) -m aat.strategy.sample.csv.readonly_periodic
$(PYTHON) -m aat.strategy.sample.csv.received

testrunsiex:
$(PYTHON) -m aat.strategy.sample.iex.readonly
TESTING=1 $(PYTHON) -m aat.strategy.sample.iex.buy_and_hold
TESTING=1 $(PYTHON) -m aat.strategy.sample.iex.momentum
TESTING=1 $(PYTHON) -m aat.strategy.sample.iex.golden_death

lint: lintpy lintjs lintcpp ## run all linters

Expand Down
1 change: 1 addition & 0 deletions aat/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .common import AATException # noqa: F401
from .config import * # noqa: F401, F403
from .core import ( # noqa: F401
EventHandler,
Expand Down
6 changes: 5 additions & 1 deletion aat/config/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,11 @@ def getStrategies(strategies: List) -> List:
args = strategy[1:]
else:
mod, clazz = strategy.split(":")
args = []
if "," in clazz:
clazz, temp_args = clazz.split(",", maxsplit=1)
args = temp_args.split(",")
else:
args = []
mod = importlib.import_module(mod)
clazz = getattr(mod, clazz)
strategy_instances.append(clazz(*args))
Expand Down
14 changes: 7 additions & 7 deletions aat/core/order_book/order_book/lite.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Callable, List, Mapping, Optional
from typing import Any, List, Mapping, Optional

from aat.core import Order, Instrument
from aat.config import Side, OrderType
Expand All @@ -17,29 +17,29 @@ class OrderBookLite(OrderBook):
Args:
instrument (Instrument): the instrument for the book
exchange_name (str): name of the exchange
callback (Function): callback on events
"""

def __init__(
self,
instrument: Instrument,
exchange_name: str = "",
callback: Optional[Callable] = None,
*args: Any,
**kwargs: Any,
):
super().__init__(
instrument=instrument, exchange_name=exchange_name, callback=callback
instrument=instrument,
exchange_name=exchange_name,
)

@staticmethod
def fromPriceLevels(
instrument: Instrument,
exchange_name: str = "",
callback: Optional[Callable] = None,
price_levels: Optional[Mapping[Side, List[PriceLevelRO]]] = None,
) -> "OrderBookLite":
"""construct order book from price levels"""
price_levels = price_levels or {}
obl = OrderBookLite(instrument, exchange_name, callback)
obl = OrderBookLite(instrument, exchange_name)

# create one order per price level
for level in price_levels[Side.SELL]:
Expand Down Expand Up @@ -79,7 +79,7 @@ def fromOrderBook(ob: OrderBook) -> "OrderBookLite":

def clone(self) -> "OrderBookLite":
"""clone an order book. useful when you want to do experiments on an orderbook without destroying it"""
obl = OrderBookLite(self.instrument, self.exchange.name, self.callback)
obl = OrderBookLite(self.instrument, self.exchange.name)

# create one order per price level
for level in self._sell_levels:
Expand Down
4 changes: 2 additions & 2 deletions aat/engine/dispatch/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def portfolioManager(self) -> PortfolioManager:
def strategies(self) -> List["Strategy"]:
return self._engine.strategies

def exchanges(self) -> List[Exchange]:
def exchangeinstances(self) -> List[Exchange]:
return self._engine.exchanges

# ********************* #
Expand Down Expand Up @@ -161,7 +161,7 @@ async def onStart(self, event: Event) -> None:
self._portfolio_mgr.updateStrategies(self.strategies())

# Initialize positions
for exchange in self.exchanges():
for exchange in self.exchangeinstances():
if self._load_accounts:
acc = await exchange.accounts()
self._portfolio_mgr.updateAccount(acc)
Expand Down
12 changes: 10 additions & 2 deletions aat/engine/dispatch/portfolio/portfolio.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,16 @@ def updateAccount(self, positions: List[Position]) -> None:
print("Position:\n{}".format(position))

try:
choice = int(
input("Select a strategy to attribute to:\n{}\n...".format(options))
choice = (
int(
input(
"Select a strategy to attribute to:\n{}\n...".format(
options
)
)
)
if len(options) > 1
else 0
)
except KeyboardInterrupt:
raise
Expand Down
36 changes: 29 additions & 7 deletions aat/engine/dispatch/utils.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import asyncio
from datetime import datetime
from typing import Any, List, Callable, Union, Optional, TYPE_CHECKING
from typing import Any, Callable, List, Optional, Union, TYPE_CHECKING

from aat.config import ExitRoutine
from aat.core import Instrument, ExchangeType, Event, Order, Trade
from aat import AATException
from aat.config import ExitRoutine, InstrumentType, TradingType
from aat.core import Instrument, ExchangeType, Event, Order, Trade, OrderBook
from aat.exchange import Exchange
from aat.config import InstrumentType, TradingType

from .periodic import Periodic

Expand Down Expand Up @@ -41,15 +41,26 @@ def instruments(
"""Return list of all available instruments"""
return Instrument._instrumentdb.instruments(type=type, exchange=exchange)

async def subscribe(
self, instrument: Instrument = None, strategy: "Strategy" = None
) -> None:
def exchanges(self, type: InstrumentType = None) -> List[ExchangeType]:
"""Return list of all available exchanges"""
if type:
raise NotImplementedError()
return [exc.exchange() for exc in self._exchanges]

async def subscribe(self, instrument: Instrument, strategy: "Strategy") -> None:
"""Subscribe to market data for the given instrument"""
if strategy not in self._data_subscriptions:
self._data_subscriptions[strategy] = []

self._data_subscriptions[strategy].append(instrument)

if instrument.exchange not in self.exchanges():
raise AATException(
"Exchange not installed: {} (Installed are [{}]".format(
instrument.exchange, self.exchanges()
)
)

for exc in self._exchanges:
if instrument and instrument.exchange == exc.exchange():
await exc.subscribe(instrument)
Expand Down Expand Up @@ -83,6 +94,17 @@ async def lookup(
# None implement
raise NotImplementedError()

async def book(self, instrument: Instrument) -> Optional[OrderBook]:
"""Return list of all available instruments that match the instrument given"""
if instrument.exchange not in self.exchanges():
raise AATException("")

for exchange_inst in self._exchanges:
if instrument.exchange == exchange_inst.exchange():
return await exchange_inst.book(instrument)

return None

def _make_async(self, function: Callable) -> Callable:
async def _wrapper() -> Any:
return await self.loop().run_in_executor(
Expand Down
1 change: 1 addition & 0 deletions aat/engine/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ def __init__(self, **config: dict) -> None:
self.strategies = getStrategies(
config.get("strategy", {}).get("strategies", [])
)

for strategy in self.strategies:
self.log.critical("Installing strategy: {}".format(strategy))
self.registerHandler(strategy)
Expand Down
7 changes: 5 additions & 2 deletions aat/exchange/base/market_data.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from abc import ABCMeta
from typing import List, AsyncIterator
from typing import AsyncIterator, List, Optional

from aat import Instrument, Event
from aat import Instrument, Event, OrderBook


class _MarketData(metaclass=ABCMeta):
Expand All @@ -17,3 +17,6 @@ async def subscribe(self, instrument: Instrument) -> None:

async def tick(self) -> AsyncIterator[Event]:
"""return data from exchange"""

async def book(self, instrument: Instrument) -> Optional[OrderBook]:
"""return order book"""

0 comments on commit a61ff9a

Please sign in to comment.