Skip to content

Commit

Permalink
Merge pull request #158 from AsyncAlgoTrading/ibfix
Browse files Browse the repository at this point in the history
Fix some race conditions, revamp ib processing
  • Loading branch information
timkpaine authored Mar 14, 2023
2 parents de79325 + f8356fe commit bb95341
Show file tree
Hide file tree
Showing 136 changed files with 21,493 additions and 13,886 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:

strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
os: [ubuntu-latest, macos-latest]
python-version: [3.9]
node-version: [14.x]
event-name: [push]
Expand Down
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ include Makefile
include aat/*.so
include aat/*.dll
include aat/*.dylib
include *.csv

graft aat/tests

Expand Down
9 changes: 8 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,14 @@ testpycpp: ## Make unit tests
# AAT_USE_CPP=1 $(PYTHON) -m pytest -vvv ./aat/tests --cov=aat --junitxml=python_junit.xml --cov-report=xml --cov-branch --capture=no
AAT_USE_CPP=1 $(PYTHON) -m pytest -vs ./aat/tests

testruns: testrunscsv testrunsiex ## Run a few examples as a live end-to-end test
testjs: ## Make js tests
cd js; yarn test

testruns: testrunscsv testrunsiex testrunsother ## Run a few examples as a live end-to-end test

testrunsother:
$(PYTHON) -m aat.exchange.test.harness
$(PYTHON) -m aat.tests.exchange.test_ib_race

testrunscsv:
$(PYTHON) -m aat.strategy.sample.csv.readonly
Expand Down
10 changes: 8 additions & 2 deletions aat/config/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import itertools
import os
import os.path
import pytz
from configparser import ConfigParser
from typing import Any, Dict, List, Union, TYPE_CHECKING
from typing import Optional, Any, Dict, List, Union, TYPE_CHECKING

if TYPE_CHECKING:
from aat.config import TradingType
Expand Down Expand Up @@ -43,6 +44,7 @@ def _args_to_dict(args: Any) -> dict:
ret["general"]["trading_type"] = args.trading_type
ret["general"]["load_accounts"] = args.load_accounts
ret["general"]["api"] = args.api
ret["general"]["timezone"] = args.timezone
ret["exchange"] = {
"exchanges": list(
_.split(",") for _ in itertools.chain.from_iterable(args.exchanges)
Expand Down Expand Up @@ -98,7 +100,7 @@ def getExchanges(
return exchange_instances


def parseConfig(argv: list = None) -> dict:
def parseConfig(argv: Optional[list] = None) -> dict:
from aat import TradingType

parser = argparse.ArgumentParser()
Expand All @@ -113,6 +115,10 @@ def parseConfig(argv: list = None) -> dict:
"--api", action="store_true", help="Enable HTTP server", default=False
)

parser.add_argument(
"--timezone", help="Timezone override", default="", choices=pytz.all_timezones
)

parser.add_argument(
"--load_accounts",
action="store_true",
Expand Down
6 changes: 3 additions & 3 deletions aat/core/data/cpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ def _make_cpp_order(
order_type: OrderType = OrderType.MARKET,
flag: OrderFlag = OrderFlag.NONE,
stop_target: Optional["Order"] = None,
id: str = None,
timestamp: datetime = None,
id: Optional[str] = None,
timestamp: Optional[datetime] = None,
) -> OrderCpp:
"""helper method to ensure all arguments are setup"""
return OrderCpp(
Expand All @@ -72,7 +72,7 @@ def _make_cpp_order(
def _make_cpp_trade(
id: str,
timestamp: datetime,
maker_orders: List["Order"] = None,
maker_orders: Optional[List["Order"]] = None,
taker_order: Optional["Order"] = None,
) -> TradeCpp:
"""helper method to ensure all arguments are setup"""
Expand Down
5 changes: 5 additions & 0 deletions aat/core/data/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ def __init__(
def timestamp(self) -> int:
return self.__timestamp

@timestamp.setter
def timestamp(self, timestamp: datetime) -> None:
assert isinstance(timestamp, datetime)
self.__timestamp = timestamp

@property
def type(self) -> DataType:
return self.__type
Expand Down
6 changes: 6 additions & 0 deletions aat/core/data/order.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,12 @@ def __repr__(self) -> str:

def __eq__(self, other: object) -> bool:
assert isinstance(other, Order)

# id takes precedence
if self.id and self.id == other.id:
return True

# else compare all fields
return (
self.id == other.id
and self.instrument == other.instrument
Expand Down
13 changes: 9 additions & 4 deletions aat/core/data/trade.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,6 @@ def __init__(
# ******** #
# Readonly #
# ******** #
@property
def timestamp(self) -> datetime:
return self.taker_order.timestamp

@property
def type(self) -> DataType:
return self.__type
Expand Down Expand Up @@ -108,6 +104,15 @@ def id(self, id: str) -> None:
assert isinstance(id, (str, int))
self.__id = str(id)

@property
def timestamp(self) -> datetime:
return self.taker_order.timestamp

@timestamp.setter
def timestamp(self, timestamp: datetime) -> None:
assert isinstance(timestamp, datetime)
self.taker_order.timestamp = timestamp

@property
def maker_orders(self) -> List[Order]:
# no setter
Expand Down
6 changes: 4 additions & 2 deletions aat/core/exchange/db.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Dict, TYPE_CHECKING
from typing import Optional, Dict, TYPE_CHECKING
from ...config import InstrumentType

if TYPE_CHECKING:
Expand Down Expand Up @@ -27,7 +27,9 @@ def instruments(
) -> None:
raise NotImplementedError()

def get(self, name: str = "", instrument: "Instrument" = None) -> "ExchangeType":
def get(
self, name: str = "", instrument: Optional["Instrument"] = None
) -> "ExchangeType":
if name:
return self._name_map[name]
raise NotImplementedError()
4 changes: 2 additions & 2 deletions aat/core/instrument/calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ class TradingDay(object):

def __init__(
self,
open_times: Union[time, Tuple[time, ...]] = None,
close_times: Union[time, Tuple[time, ...]] = None,
open_times: Optional[Union[time, Tuple[time, ...]]] = None,
close_times: Optional[Union[time, Tuple[time, ...]]] = None,
):
if open_times and not isinstance(open_times, (tuple, time)):
# raise exception if wrong type
Expand Down
9 changes: 7 additions & 2 deletions aat/core/instrument/cpp.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Any
from typing import Any, List

from aat.common import _in_cpp

Expand All @@ -12,4 +12,9 @@


def _make_cpp_instrument(*args: Any, **kwargs: Any) -> InstrumentCpp:
return InstrumentCpp(*args, **kwargs)
if kwargs:
full_args: List[Any] = list(args)
full_args.append(kwargs.get("name"))
full_args.append(kwargs.get("type"))
args = tuple(full_args)
return InstrumentCpp(*args)
8 changes: 6 additions & 2 deletions aat/core/instrument/instrument.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,9 @@ def exchanges(self) -> List[ExchangeType]:
def exchange(self) -> ExchangeType:
return self.__exchange

def tradingLines(self, exchange: ExchangeType = None) -> List["Instrument"]:
def tradingLines(
self, exchange: Optional[ExchangeType] = None
) -> List["Instrument"]:
"""Returns other exchanges that the same instrument trades on
Returns:
Expand All @@ -312,7 +314,9 @@ def tradingLines(self, exchange: ExchangeType = None) -> List["Instrument"]:
return self._instrumentdb.instruments(self.name, self.type, exchange)

def synthetics(
self, type: InstrumentType = None, exchange: ExchangeType = None
self,
type: Optional[InstrumentType] = None,
exchange: Optional[ExchangeType] = None,
) -> List["Instrument"]:
"""Returns other instruments with the same name
Expand Down
2 changes: 1 addition & 1 deletion aat/core/order_book/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def spread(self) -> float:
pass

@abstractmethod
def level(self, level: int = 0, price: float = None) -> Tuple:
def level(self, level: int = 0, price: Optional[float] = None) -> Tuple:
pass

@abstractmethod
Expand Down
3 changes: 1 addition & 2 deletions aat/core/order_book/order_book/order_book.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ def __init__(
exchange_name: Union[ExchangeType, str] = "",
callback: Optional[Callable] = None,
) -> None:

self._instrument = instrument
self._exchange_name: ExchangeType = (
exchange_name
Expand Down Expand Up @@ -164,7 +163,7 @@ def spread(self) -> float:
tob: Dict[Side, PriceLevelRO] = self.topOfBook()
return tob[Side.SELL].price - tob[Side.BUY].price

def level(self, level: int = 0, price: float = None) -> Tuple:
def level(self, level: int = 0, price: Optional[float] = None) -> Tuple:
"""return book level
Args:
Expand Down
4 changes: 2 additions & 2 deletions aat/core/order_book/price_level/ro.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from collections import deque
from typing import Deque, Dict, List, Union
from typing import Optional, Deque, Dict, List, Union
from aat.core import Order


Expand All @@ -18,7 +18,7 @@ def __init__(
price: float,
volume: float,
number_of_orders: int = 0,
_orders: Deque[Order] = None,
_orders: Optional[Deque[Order]] = None,
):
self._price = price
self._volume = volume
Expand Down
2 changes: 1 addition & 1 deletion aat/cpp/include/aat/core/data/data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ namespace core {
, instrument(instrument)
, exchange(exchange)
, data(data) {}

virtual ~Data() {}
bool operator==(const Data& other);
virtual str_t toString() const;
virtual json toJson() const;
Expand Down
3 changes: 3 additions & 0 deletions aat/cpp/include/aat/core/data/order.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ namespace core {
Order(str_t id, timestamp_t timestamp, double volume, double price, Side side, Instrument& instrument,
ExchangeType& exchange = NullExchange, double notional = 0.0, OrderType order_type = OrderType::MARKET,
OrderFlag flag = OrderFlag::NONE, std::shared_ptr<Order> stop_target = nullptr);
virtual ~Order() {}

virtual bool operator==(Order& other) const;

bool finished() const;
void finish();
Expand Down
1 change: 1 addition & 0 deletions aat/cpp/include/aat/core/data/trade.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ namespace core {
// enforce that stop target match stop type
// assert(maker_orders.size() > 0); // not necessarily
}
virtual ~Trade() {}

double
slippage() const {
Expand Down
2 changes: 2 additions & 0 deletions aat/cpp/include/aat/core/exchange/exchange.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ namespace core {
explicit ExchangeType(str_t name)
: name(name) {}

virtual ~ExchangeType() {}

str_t toString() const;
virtual json toJson() const;

Expand Down
1 change: 1 addition & 0 deletions aat/cpp/include/aat/core/instrument/instrument.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace core {
: name(name)
, type(InstrumentType::EQUITY) {}

virtual ~Instrument() {}
bool operator==(const Instrument& other) const;
str_t toString() const;
virtual json toJson() const;
Expand Down
13 changes: 12 additions & 1 deletion aat/cpp/include/aat/python/binding.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,18 @@ PYBIND11_MODULE(binding, m) {
.export_values();

py::enum_<InstrumentType>(m, "InstrumentTypeCpp", py::arithmetic())
.value("CURRENCY", InstrumentType::CURRENCY)
.value("OTHER", InstrumentType::OTHER)
.value("EQUITY", InstrumentType::EQUITY)
.value("BOND", InstrumentType::BOND)
.value("OPTION", InstrumentType::OPTION)
.value("FUTURE", InstrumentType::FUTURE)
.value("PAIR", InstrumentType::PAIR)
.value("SPREAD", InstrumentType::SPREAD)
.value("FUTURESOPTION", InstrumentType::FUTURESOPTION)
.value("MUTUALFUND", InstrumentType::MUTUALFUND)
.value("COMMODITY", InstrumentType::COMMODITY)
.value("CURRENCY", InstrumentType::CURRENCY)
.value("INDEX", InstrumentType::INDEX)
.export_values();

py::enum_<OrderType>(m, "OrderTypeCpp", py::arithmetic())
Expand Down Expand Up @@ -198,6 +208,7 @@ PYBIND11_MODULE(binding, m) {
py::arg("exchange").none(false), py::arg("notional").none(false), py::arg("order_type").none(false),
py::arg("flag").none(false), py::arg("stop_target").none(true))
.def("__repr__", &Order::toString)
.def("__eq__", &Order::operator==)
.def("finished", &Order::finished)
.def("finish", &Order::finish)
.def("json", &Order::toJson)
Expand Down
5 changes: 5 additions & 0 deletions aat/cpp/src/core/data/order.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ namespace core {
}
}

bool
Order::operator==(Order& other) const {
return this->id == other.id;
}

bool
Order::finished() const {
return (volume == filled) || force_done;
Expand Down
5 changes: 1 addition & 4 deletions aat/cpp/src/core/order_book/order_book.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -475,8 +475,6 @@ namespace core {
// show top 5 levels, then group next 5, 10, 20, etc
// sells first
std::vector<std::shared_ptr<PriceLevel>> sells_to_print;
auto count = 5;
auto orig = 5;

for (std::uint64_t i = 0; i < sell_levels.size(); ++i) {
if (i < 5) {
Expand All @@ -494,8 +492,7 @@ namespace core {
// show top 5 levels, then group next 5, 10, 20, etc
// buys second
std::vector<std::shared_ptr<PriceLevel>> buys_to_print;
count = 5;
orig = 5;

int i = 0;

for (auto iter = buy_levels.end() - 1; iter > buy_levels.begin(); --iter) {
Expand Down
6 changes: 3 additions & 3 deletions aat/cpp/src/core/position/cash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ namespace aat {
namespace core {

CashPosition::CashPosition(double notional, timestamp_t timestamp, Instrument& instrument, ExchangeType& exchange)
: instrument(instrument)
: timestamp(timestamp)
, instrument(instrument)
, exchange(exchange)
, notional(notional)
, timestamp(timestamp) {
, notional(notional) {
notional_history.push_back(notional);
notional_timestamps.push_back(timestamp);
}
Expand Down
4 changes: 2 additions & 2 deletions aat/cpp/src/core/position/position.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ namespace core {

Position::Position(double size, double price, timestamp_t timestamp, Instrument& instrument, ExchangeType& exchange,
std::vector<std::shared_ptr<Trade>>& trades)
: instrument(instrument)
: timestamp(timestamp)
, instrument(instrument)
, exchange(exchange)
, size(size)
, price(price)
, timestamp(timestamp)
, investment(size * price)
, notional(size * price)
, instrumentPrice(price)
Expand Down
Loading

0 comments on commit bb95341

Please sign in to comment.