Skip to content

Commit

Permalink
Merge pull request #112 from AsyncAlgoTrading/ib_partial_fill
Browse files Browse the repository at this point in the history
Ib partial fill
  • Loading branch information
timkpaine committed Oct 19, 2020
2 parents 11e9502 + 66e5fee commit d422787
Show file tree
Hide file tree
Showing 11 changed files with 91 additions and 11 deletions.
10 changes: 10 additions & 0 deletions aat/core/models/order.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class Order(object):
"__order_type",
"__flag",
"__stop_target",
"__force_done",
]

# for convenience
Expand Down Expand Up @@ -77,6 +78,7 @@ def __init__(self, volume, price, side, instrument, exchange=ExchangeType(""), n
self.__stop_target = stop_target

self.__filled = 0.0
self.__force_done = False

# TODO
# @validator("notional")
Expand Down Expand Up @@ -124,6 +126,14 @@ def flag(self) -> OrderFlag:
def stop_target(self) -> Union['Order', None]:
return self.__stop_target

def finished(self) -> bool:
return (self.volume == self.filled) or self.__force_done

def finish(self) -> None:
'''force this order to mark itself as "finished", even if it
isn't fully filled (e.g. with certain flags)'''
self.__force_done = True

# ***********#
# Read/write #
# ***********#
Expand Down
3 changes: 3 additions & 0 deletions aat/core/models/trade.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ def side(self) -> Side:
def notional(self):
return self.price * self.volume

def finished(self):
return self.taker_order.finished

# ***********#
# Read/write #
# ***********#
Expand Down
1 change: 0 additions & 1 deletion aat/cpp/include/aat/core/exchange/exchange.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ namespace core {
str_t name;
};


static ExchangeType NullExchange = ExchangeType("");

} // namespace core
Expand Down
4 changes: 4 additions & 0 deletions aat/cpp/include/aat/core/models/order.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ namespace core {
ExchangeType& exchange = NullExchange, double notional = 0.0, OrderType order_type = OrderType::MARKET,
OrderFlag flag = OrderFlag::NONE, std::shared_ptr<Order> stop_target = nullptr);

bool finished() const;
void finish();

virtual str_t toString() const;
virtual json toJson() const;
virtual json perspectiveSchema() const;
Expand All @@ -39,6 +42,7 @@ namespace core {
double notional = 0.0;

double filled = 0.0;
bool force_done = false;
};

} // namespace core
Expand Down
2 changes: 2 additions & 0 deletions aat/cpp/include/aat/core/models/trade.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ namespace core {
return 0.0;
}

bool finished() const;

virtual str_t toString() const;
virtual json toJson() const;
virtual json perspectiveSchema() const;
Expand Down
3 changes: 3 additions & 0 deletions aat/cpp/include/aat/python/binding.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ 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("finished", &Order::finished)
.def("finish", &Order::finish)
.def("toJson", &Order::toJson)
.def("perspectiveSchema", &Order::perspectiveSchema)
.def_readwrite("id", &Order::id)
Expand All @@ -212,6 +214,7 @@ PYBIND11_MODULE(binding, m) {
.def("__repr__", &Trade::toString)
.def("slippage", &Trade::slippage)
.def("transactionCost", &Trade::transactionCost)
.def("finished", &Trade::finished)
.def("toJson", &Trade::toJson)
.def("perspectiveSchema", &Trade::perspectiveSchema)
.def_readwrite("id", &Trade::id)
Expand Down
10 changes: 10 additions & 0 deletions aat/cpp/src/core/models/order.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ namespace core {
}
}

bool
Order::finished() const {
return (volume == filled) || force_done;
}

void
Order::finish() {
force_done = true;
}

str_t
Order::toString() const {
sstream_t ss;
Expand Down
5 changes: 5 additions & 0 deletions aat/cpp/src/core/models/trade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ using namespace aat::common;

namespace aat {
namespace core {
bool
Trade::finished() const {
return taker_order->finished();
}

str_t
Trade::toString() const {
sstream_t ss;
Expand Down
4 changes: 3 additions & 1 deletion aat/engine/dispatch/execution/execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ async def onTrade(self, event):
else:
# TODO ugly private method
await self._manager._onBought(strat, event.target)
del self._pending_orders[order.id]

if order.finished():
del self._pending_orders[order.id]

async def onCancel(self, event):
order = event.target
Expand Down
58 changes: 50 additions & 8 deletions aat/exchange/public/ib/ib.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
from queue import Queue
from random import randint

from ibapi.contract import Contract # type: ignore
from ibapi.client import EClient # type: ignore
from ibapi.execution import Execution, ExecutionFilter # type: ignore
from ibapi.commission_report import CommissionReport # type: ignore
from ibapi.wrapper import EWrapper # type: ignore
from ibapi.contract import Contract # type: ignore

from aat.exchange import Exchange
from aat.config import EventType, TradingType, Side
Expand Down Expand Up @@ -64,14 +66,15 @@ def orderStatus(self, orderId, status, filled, remaining, avgFillPrice, permId,
self._order_event_queue.put(dict(orderId=orderId,
status=status,
filled=filled,
remaining=remaining,
# remaining=remaining, # TODO not used
avgFillPrice=avgFillPrice,
permId=permId,
parentId=parentId,
lastFillPrice=lastFillPrice,
clientId=clientId,
whyHeld=whyHeld,
mktCapPrice=mktCapPrice))
# permId=permId, # TODO not used
# parentId=parentId, # TODO not used
# lastFillPrice=lastFillPrice, # TODO not used
# clientId=clientId, # TODO not used
# whyHeld=whyHeld, # TODO not used
# mktCapPrice=mktCapPrice # TODO not used
))

def subscribeMarketData(self, instrument):
contract = _constructContract(instrument)
Expand All @@ -90,6 +93,33 @@ def cancelMarketData(self, contract):
del self._mkt_data_map_rev[contract]
del self._mkt_data_map[id]

def reqExecutions(self):
super().reqExecutions(self.nextReqId, ExecutionFilter())
self.nextReqId += 1

def execDetails(self, reqId: int, contract: Contract, execution: Execution):
super().execDetails(reqId, contract, execution)
self._order_event_queue.put(dict(orderId=execution.orderId,
status="Execution",
filled=execution.cumQty,
# remaining=-1, # TODO not available here
avgFillPrice=execution.avgPrice, # TODO execution.price?
# permId=permId, # TODO not used
# parentId=parentId, # TODO not used
# lastFillPrice=lastFillPrice, # TODO not used
# clientId=clientId, # TODO not used
# whyHeld=whyHeld, # TODO not used
# mktCapPrice=mktCapPrice # TODO not used
))

def commissionReport(self, commissionReport: CommissionReport):
super().commissionReport(commissionReport)
# TODO?

def execDetailsEnd(self, reqId: int):
super().execDetailsEnd(reqId)
# TODO?

def tickPrice(self, reqId, tickType, price, attrib):
# TODO implement more of order book

Expand Down Expand Up @@ -217,6 +247,18 @@ async def tick(self):
yield e

elif status in ('Filled',):
# this is the filled from orderStatus, but we
# want to use the one from execDetails

# From the IB Docs:
# "There are not guaranteed to be orderStatus
# callbacks for every change in order status"
# It is recommended to use execDetails

# ignore
pass

elif status in ('Execution',):
# set filled
order.filled = order_data['filled']

Expand Down
2 changes: 1 addition & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ jobs:

- job: 'Mac'
pool:
vmImage: 'macos-10.14'
vmImage: 'macos-10.15'

strategy:
matrix:
Expand Down

0 comments on commit d422787

Please sign in to comment.