Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3cd9da308 | ||
|
|
41bcfe727d | ||
|
|
07a059fb5d | ||
|
|
05ca21d517 | ||
|
|
0586df2434 | ||
|
|
e9571664f5 | ||
|
|
ca69cdec2a | ||
|
|
6500b8047d | ||
|
|
630ecae681 |
No files matched your search
Vendored
+3
-3
@@ -135,13 +135,13 @@
|
||||
"name": "Spreader Tests",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "/home/bts/spark/build/ninja_debug/src/server/sparkd/sparkd",
|
||||
"program": "/home/bts/spark/build/ninja_debug/server/sparkd",
|
||||
"args": [
|
||||
"test",
|
||||
"[spreader]"
|
||||
],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "/home/bts/spark/build/ninja_debug/src/server/sparkd/",
|
||||
"cwd": "/home/bts/spark/build/ninja_debug/server",
|
||||
"environment": [],
|
||||
"externalConsole": true,
|
||||
"MIMode": "gdb",
|
||||
@@ -288,7 +288,7 @@
|
||||
"name": "SparkVM attach",
|
||||
"type": "cppdbg",
|
||||
"request": "attach",
|
||||
"program": "/home/bts/spark/build/ninja_debug/src/server/sparkd/sparkd",
|
||||
"program": "/home/bts/spark/build/ninja_debug/server/sparkd",
|
||||
"processId": "${command:pickRemoteProcess}",
|
||||
"MIMode": "gdb",
|
||||
"pipeTransport": {
|
||||
|
||||
@@ -108,7 +108,7 @@ where
|
||||
session.session_start = event_view.session_start and
|
||||
event_view.channel=trace.channel and event_view.sn=trace.sn and
|
||||
event_type='hedge' and
|
||||
entry_kind='NativeOrder::on_activate' and
|
||||
entry_kind='NativeOrder::on_update' and
|
||||
cor_event=0;
|
||||
|
||||
/* A view on requote events, identifying each order sent as part of the event*/
|
||||
|
||||
@@ -38,6 +38,8 @@ inline api::Side other_side(api::Side side) {
|
||||
|
||||
inline double market_epislon() { return 1e-10; }
|
||||
|
||||
// this tells which price is better from a market data
|
||||
// standpoint, ie for buys the higher price is better
|
||||
inline bool is_better(api::Side side, Price p1, Price p2) {
|
||||
switch (side) {
|
||||
case api::SIDE_BUY:
|
||||
@@ -81,6 +83,12 @@ inline Price better_price (api::Side side, Price p1, Price p2){
|
||||
return is_equal_or_better(side, p1, p2) ? p1 : p2;
|
||||
}
|
||||
|
||||
// returns true if p1 is a better order price than p2
|
||||
// ie lower when buying, higher when selling
|
||||
inline bool same_or_better_order_price (api::Side side, Price p1, Price p2){
|
||||
return is_equal_or_better(side, p2, p1);
|
||||
}
|
||||
|
||||
inline Price decode_exchange_price(api::Security const &sec, Price in) {
|
||||
return Price(in.value() * sec.contract_spec().price_multiplier());
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ public:
|
||||
for (auto& o : _orders){
|
||||
// is_cancelled() is checked so as not to keep
|
||||
// sending cancel requests
|
||||
if(!o.is_cancelled()&&o.acknowledged()&&!o.terminal_status())
|
||||
if(!o.cancel_sent()&&o.acknowledged()&&!o.terminal_status())
|
||||
o.cancel_order();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,6 +118,12 @@ ChildOrder SpreaderOrder::get_new_hedge_order(size_t leg_index){
|
||||
bts::orderman::ChildOrder child_order = leg_data.hedger_order_builder().build();
|
||||
return child_order;
|
||||
}
|
||||
void SpreaderOrder::send_hedge_order (size_t hedge_leg_index,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty,
|
||||
bool use_quoting_order){
|
||||
_send_hedge(hedge_leg_index, hedge_price, hedge_qty, use_quoting_order);
|
||||
}
|
||||
// events from orders system ////////////////////
|
||||
/////////////////////////////////////////////////
|
||||
void SpreaderOrder::_on_time(const bts::mercury::TimerEvent& t_event){
|
||||
@@ -368,10 +374,12 @@ bool SpreaderOrder::_quoters_can_accept_modification (){
|
||||
}
|
||||
void SpreaderOrder::_send_hedge(size_t hedge_leg_index,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty){
|
||||
Quantity hedge_qty,
|
||||
bool use_quoting_order){
|
||||
_bookkeeping_data().add_new_hedger (hedge_leg_index,
|
||||
hedge_price,
|
||||
hedge_qty);
|
||||
hedge_qty,
|
||||
use_quoting_order);
|
||||
}
|
||||
void SpreaderOrder::_compute_hedge_price_quantity(size_t filled_leg_index,
|
||||
Price fill_price,
|
||||
|
||||
@@ -140,10 +140,13 @@ public:
|
||||
}
|
||||
void setup_new_quoter_order (size_t leg_index) override;
|
||||
ChildOrder get_new_hedge_order (size_t leg_index) override;
|
||||
void send_hedge_order (size_t hedge_leg_index,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty,
|
||||
bool use_quoting_order = false) override;
|
||||
inline bool in_cache_warming_cycle() const override{
|
||||
return _cw_helper.in_cache_warming_cycle;
|
||||
}
|
||||
|
||||
private:
|
||||
// events from orders system ////////////////////
|
||||
/////////////////////////////////////////////////
|
||||
@@ -235,7 +238,8 @@ private:
|
||||
// quantity 'filled_quantity'
|
||||
void _send_hedge(size_t hedge_leg_index,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty);
|
||||
Quantity hedge_qty,
|
||||
bool use_quoting_order);
|
||||
void _compute_hedge_price_quantity(size_t filled_leg_index,
|
||||
Price filled_price,
|
||||
double filled_quantity,
|
||||
|
||||
@@ -7,12 +7,17 @@ namespace orderman {
|
||||
|
||||
class LegPropertyData;
|
||||
class CacheWarmingState;
|
||||
class SpreaderChildOrderState;
|
||||
// The Spreader spawns a bunch of quoters and
|
||||
// hedgers and hands them this interface to
|
||||
// i. get data such as book and leg properties
|
||||
// (in O(1) access time)
|
||||
// ii. create new quoter order
|
||||
class ISpreaderManager{
|
||||
public:
|
||||
struct OrderTransfer{
|
||||
SpreaderChildOrderState* q_order;
|
||||
};
|
||||
public:
|
||||
virtual bts::orderman::OrderKey spreader_order_key() const = 0;
|
||||
virtual bts::TimeStamp current_time() const = 0;
|
||||
@@ -28,6 +33,14 @@ public:
|
||||
// it does not alter the state or has side effects (as
|
||||
// as the spreader goes)
|
||||
virtual ChildOrder get_new_hedge_order (size_t leg_index) = 0;
|
||||
// sends a new hedge for the leg index at a specified
|
||||
// hedge price and size. when use_quoting_order is
|
||||
// set to true the hegder is passed over the quoting
|
||||
// order (and its state) to hedge
|
||||
virtual void send_hedge_order (size_t hedge_leg_index,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty,
|
||||
bool use_quoting_order) = 0;
|
||||
// the spreader can be in a cache warming cycle and generate
|
||||
// fake updates, the quoters and hedgers should ignore them
|
||||
// (however do as much as they can to keep the instruction
|
||||
|
||||
@@ -35,7 +35,9 @@ public:
|
||||
const bts::api::Security& security() const { return _leg_contract.security(); }
|
||||
double price_multiplier() const { return _leg_contract.price_multiplier(); }
|
||||
double size_multiplier() const { return _leg_contract.quantity(); }
|
||||
double tick_size() const { return _leg_contract.security().contract_spec().low_tick(); }
|
||||
double tick_size() const {
|
||||
return _leg_contract.security().contract_spec().low_tick();
|
||||
}
|
||||
bool is_active_quoting() const {return _leg_params.is_active_quoting();}
|
||||
bool is_net_change() const{
|
||||
return _price_calc==bts::api::SyntheticContract::PRICECALC_NET_CHANGE;
|
||||
@@ -56,6 +58,9 @@ public:
|
||||
uint32_t n_queue_holder_orders() const{
|
||||
return _leg_params.quote_params().n_queue_holder_orders();
|
||||
}
|
||||
bts::spark::UseSpreaderQuoteForHedging use_quote_for_hedging() const{
|
||||
return _leg_params.quote_params().use_quote_for_hedging();
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
@@ -83,8 +83,9 @@ _end_state_worker (this, other._end_state_worker){
|
||||
/****************************External Calls**************************/
|
||||
/********************************************************************/
|
||||
void SingleFillHedger::init_hedger (Price price,
|
||||
Quantity quantity){
|
||||
_worker->init(price,quantity);
|
||||
Quantity quantity,
|
||||
ISpreaderManager::OrderTransfer* order){
|
||||
_worker->init(price, quantity, order);
|
||||
}
|
||||
void SingleFillHedger::on_order_update(const SpreaderChildOrderState& u){
|
||||
//bts_assert (u.order_key() == _order.order_key());
|
||||
@@ -138,7 +139,9 @@ void SingleFillHedger::transform_to_WAITING_FOR_FIRST_ACK_CANCELLED () {
|
||||
_switch_state (&_waiting_for_first_ack_cancelled_state_worker);
|
||||
}
|
||||
void SingleFillHedger::transform_to_WORKING() {
|
||||
bts_assert(_worker->state() == HedgerState::WAITING_FOR_FIRST_ACK);
|
||||
bts_assert(_worker->state() == HedgerState::WAITING_FOR_FIRST_ACK ||
|
||||
// in case of quoting orders assigned to hedger
|
||||
_worker->state() == HedgerState::START);
|
||||
_switch_state (&_working_state_worker);
|
||||
}
|
||||
void SingleFillHedger::transform_to_WAITING_FOR_CANCEL_ACK(){
|
||||
|
||||
@@ -58,6 +58,9 @@ private:
|
||||
void _modify_order (Price new_price){
|
||||
_child_order_state.modify_order(new_price);
|
||||
}
|
||||
void _modify_order (Price new_price, Quantity qty){
|
||||
_child_order_state.modify_order(new_price, qty);
|
||||
}
|
||||
void _cancel_order () {
|
||||
_child_order_state.cancel_order();
|
||||
}
|
||||
@@ -93,7 +96,9 @@ public:
|
||||
//that live in the START state until...
|
||||
//iii.until init_hedger is called which sets the price
|
||||
//qty and causes the order to be submitted
|
||||
void init_hedger (Price price, Quantity quantity);
|
||||
void init_hedger (Price price,
|
||||
Quantity quantity,
|
||||
ISpreaderManager::OrderTransfer* order = nullptr);
|
||||
//b. called by the spreader when there is an order update
|
||||
// reported by the exchange
|
||||
void on_order_update(const SpreaderChildOrderState& order_update_message);
|
||||
|
||||
@@ -112,13 +112,17 @@ void SingleLegQuoter::on_book(size_t leg_index,
|
||||
_worker->on_book (leg_index, book);
|
||||
}
|
||||
void SingleLegQuoter::update_other_leg_fills(size_t leg_index,
|
||||
Quantity filled_quantity){
|
||||
Quantity filled_quantity,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty){
|
||||
bts_assert(_active_quoting);
|
||||
LOG(OrderMan, Info, "SingleLegQuoter::update_other_leg_fills "
|
||||
"spread_key:{} leg_idx:{} fill_idx:{} filled_quantity:{}",
|
||||
_spreader.spreader_order_key(), _this_leg_data.leg_index(),
|
||||
leg_index, filled_quantity);
|
||||
_worker->on_other_leg_quoter_fill (leg_index, filled_quantity);
|
||||
if(hedge_qty.value()>0)
|
||||
LOG(OrderMan, Info, "SingleLegQuoter::update_other_leg_fills "
|
||||
"spread_key:{} leg_idx:{} fill_idx:{} filled_quantity:{}",
|
||||
_spreader.spreader_order_key(), _this_leg_data.leg_index(),
|
||||
leg_index, filled_quantity);
|
||||
_worker->on_other_leg_quoter_fill (leg_index, filled_quantity,
|
||||
hedge_price, hedge_qty);
|
||||
}
|
||||
void SingleLegQuoter::update_order_price_quantity(Price price,
|
||||
Quantity quantity){
|
||||
@@ -161,8 +165,18 @@ bool SingleLegQuoter::accept_modifications() const {
|
||||
return _worker->state() == QuoterState::WAITING_FOR_SIZE ||
|
||||
_worker->state() == QuoterState::WORKING;
|
||||
}
|
||||
void SingleLegQuoter::_incorporate_other_leg_fill (size_t, Quantity hedge_reduction){
|
||||
void SingleLegQuoter::_incorporate_other_leg_fill (size_t,
|
||||
Quantity hedge_reduction,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty,
|
||||
bool send_new_hedge,
|
||||
bool use_quoting_order){
|
||||
_price_quantity_state.add_hedged_reduction (hedge_reduction);
|
||||
if(send_new_hedge)
|
||||
_spreader.send_hedge_order(_this_leg_data.leg_index(),
|
||||
hedge_price,
|
||||
hedge_qty,
|
||||
use_quoting_order);
|
||||
}
|
||||
void SingleLegQuoter::_compute_quote(
|
||||
Quantity target_qty,
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWaitingForCancelAckStateWorker.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWorkingStateWorker.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterEndStateWorker.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWaitingForOrderTransferStateWorker.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/quoter/QuoteLegDriver.h"
|
||||
#include "lib/orderman/actors/order_manager/ChildOrder.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/SpreaderChildOrderState.h"
|
||||
@@ -35,6 +36,7 @@ friend QuoterWaitingForIOCWorker;
|
||||
friend QuoterWaitingForFirstAckCancelledWorker;
|
||||
friend QuoterWaitingForCancelAckStateWorker;
|
||||
friend QuoterWorkingStateWorker;
|
||||
friend QuoterWaitingForOrderTransferStateWorker;
|
||||
friend QuoterEndStateWorker;
|
||||
private:
|
||||
const bool _two_legged;
|
||||
@@ -115,7 +117,9 @@ public:
|
||||
//g. this is called by the spreader when a quoting fill
|
||||
// (ie not hedging fill) happens on one of the quoting
|
||||
// legs
|
||||
void update_other_leg_fills(size_t leg_index, Quantity filled_quantity);
|
||||
void update_other_leg_fills(size_t leg_index, Quantity filled_quantity,
|
||||
Price hedge_price = Price(0),
|
||||
Quantity hedge_qty = Quantity(0));
|
||||
//h. called when the user modified the spreader order price or quantity
|
||||
void update_order_price_quantity(Price price, Quantity quantity);
|
||||
// true if the quoter has an active working order. the order can
|
||||
@@ -181,7 +185,12 @@ private:
|
||||
}
|
||||
void _cancel_order () {_child_order_state.cancel_order();}
|
||||
// this updates the hedge reduction in _price_quantity_state
|
||||
void _incorporate_other_leg_fill (size_t leg_index, Quantity hedge_reduction);
|
||||
void _incorporate_other_leg_fill (size_t leg_index,
|
||||
Quantity hedge_reduction,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty,
|
||||
bool send_new_hedge = true,
|
||||
bool use_quoting_order_to_hedge = false);
|
||||
// given a target quoting qty
|
||||
// this figures out the price and the actual
|
||||
// qty that can be quoted.
|
||||
|
||||
@@ -103,12 +103,16 @@ public:
|
||||
// and returns a ref to it
|
||||
// (dont keep pointers to hedgers since the vector
|
||||
// can resize)
|
||||
inline SingleFillHedger& add_new_hedger(size_t leg_index,
|
||||
inline SingleFillHedger& add_new_hedger(
|
||||
size_t leg_index,
|
||||
Price hedge_price,
|
||||
Quantity hedge_quantity){
|
||||
Quantity hedge_quantity,
|
||||
bool use_quoting_order = false){
|
||||
bts_assert(leg_index < _leg_data.size());
|
||||
SpreaderLegData& leg_data=_leg_data[leg_index];
|
||||
return leg_data.add_new_hedger(hedge_price,hedge_quantity);
|
||||
return leg_data.add_new_hedger(hedge_price,
|
||||
hedge_quantity,
|
||||
use_quoting_order);
|
||||
}
|
||||
// finds the spreader fill, price (ie averages it out, using
|
||||
// the size and price ratio, across all legs)
|
||||
|
||||
@@ -10,18 +10,20 @@ _is_live(src._is_live),
|
||||
_sec_key(src._sec_key),
|
||||
_is_quoting (src._is_quoting),
|
||||
_test_only_order_key(src._test_only_order_key),
|
||||
_base_price(src._base_price),
|
||||
_base_quantity(src._base_quantity),
|
||||
_n_place_orders(src._n_place_orders),
|
||||
_n_cancel_orders(src._n_cancel_orders),
|
||||
_n_modify_orders(src._n_modify_orders),
|
||||
_base_price(src._base_price),
|
||||
_base_quantity(src._base_quantity),
|
||||
_child_order(std::move(src._child_order)),
|
||||
_handover_filled_qty(Quantity(0)),
|
||||
_status(src._status),
|
||||
_filled_price(src._filled_price),
|
||||
_filled_quantity(src._filled_quantity),
|
||||
_last_filled_price(src._last_filled_price),
|
||||
_last_update_filled_price(src._last_update_filled_price),
|
||||
_last_update_filled_quantity(src._last_update_filled_quantity),
|
||||
_last_reported_order_price(src._last_reported_order_price),
|
||||
_last_filled_quantity(src._last_filled_quantity),
|
||||
_last_reported_order_qty(src._last_reported_order_qty),
|
||||
_out_price(src._out_price),
|
||||
_out_quantity(src._out_quantity),
|
||||
_order_place_time(src._order_place_time)
|
||||
@@ -40,7 +42,8 @@ _base_quantity(0){
|
||||
ChildOrder& empty_order=_empty_order();
|
||||
re_init(empty_order);
|
||||
}
|
||||
void SpreaderChildOrderState::re_init (ChildOrder& child_order){
|
||||
void SpreaderChildOrderState::re_init (ChildOrder& child_order,
|
||||
Quantity handover_filled_qty){
|
||||
SpreaderUtils::compute_average_price(_base_price, _base_quantity,
|
||||
_filled_price, _filled_quantity,
|
||||
_base_price, _base_quantity);
|
||||
@@ -48,12 +51,14 @@ void SpreaderChildOrderState::re_init (ChildOrder& child_order){
|
||||
_n_cancel_orders = _n_modify_orders = 0;
|
||||
_child_order = ChildOrder();
|
||||
_child_order = std::move(child_order);
|
||||
_handover_filled_qty = handover_filled_qty;
|
||||
_status = bts::api::orderman::OrderStatus::ORDER_STATUS_INACTIVE;
|
||||
_filled_price = Price(0);
|
||||
_filled_quantity = Quantity (0);
|
||||
_last_filled_price = Price(0);
|
||||
_last_update_filled_price = Price(0);
|
||||
_last_update_filled_quantity = Quantity(0);
|
||||
_last_reported_order_price=Price(0);
|
||||
_last_filled_quantity = Quantity(0);
|
||||
_last_reported_order_qty=Quantity(0);
|
||||
_out_price = Price(0);
|
||||
_out_quantity = Quantity(0);
|
||||
_order_place_time=bts::TimeStamp();
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "lib/api/services/OrderService.pb.h"
|
||||
#include "lib/orderman/events/OrderStateUpdateEvent.h"
|
||||
#include "SpreaderUtils.h"
|
||||
#include "lib/domain_model/Security.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
@@ -20,17 +21,22 @@ private:
|
||||
const SecurityKey _sec_key;
|
||||
const bool _is_quoting;
|
||||
const OrderKey _test_only_order_key;
|
||||
// Since SpreaderChildOrderState can be assigned
|
||||
// multiple ChildOrders during its lifetime, the
|
||||
// accumulated fills and fill price from previous
|
||||
// orders is kept here
|
||||
Price _base_price;
|
||||
Quantity _base_quantity;
|
||||
// just for statistics
|
||||
uint16_t _n_place_orders, _n_cancel_orders;
|
||||
uint32_t _n_modify_orders;
|
||||
// while child orders can recycle, their
|
||||
// accumulated price, qty is kept here
|
||||
Price _base_price;
|
||||
Quantity _base_quantity;
|
||||
ChildOrder _child_order;
|
||||
ChildOrder _child_order;
|
||||
// If the child order handled through re_init already
|
||||
// is in a working state with fills
|
||||
Quantity _handover_filled_qty;
|
||||
api::orderman::OrderStatus _status;
|
||||
// this is the total filled qty and
|
||||
// average price for the active order
|
||||
// average filled price for the active order
|
||||
Price _filled_price;
|
||||
Quantity _filled_quantity;
|
||||
// this is the fill price, qty reported
|
||||
@@ -38,16 +44,23 @@ private:
|
||||
// (if no fill was reported but it was
|
||||
// merely an order update, the qty
|
||||
// here will be 0).
|
||||
// _last_reported_order_price is the
|
||||
// the working order price as it was
|
||||
// last reported
|
||||
Price _last_filled_price;
|
||||
Price _last_reported_order_price;
|
||||
Quantity _last_filled_quantity;
|
||||
// this is latest price, qty sent out
|
||||
Price _last_update_filled_price;
|
||||
Quantity _last_update_filled_quantity;
|
||||
// these are the order price and qty reported
|
||||
// in the last update (this is the best knowledge
|
||||
// of what is out there)
|
||||
Price _last_reported_order_price;
|
||||
Quantity _last_reported_order_qty;
|
||||
// this is last price, qty sent out through
|
||||
// the place_order or modify_order calls
|
||||
Price _out_price;
|
||||
Quantity _out_quantity;
|
||||
Quantity _out_quantity;
|
||||
bts::TimeStamp _order_place_time;
|
||||
private:
|
||||
bool _change_in_flight() const{
|
||||
return !securities::is_same(_out_price, _last_reported_order_price) ||
|
||||
_out_quantity != _last_reported_order_qty;
|
||||
}
|
||||
public:
|
||||
// constructors ///////////////////
|
||||
///////////////////////////////////
|
||||
@@ -56,37 +69,52 @@ public:
|
||||
SpreaderChildOrderState(SecurityKey sec_key,
|
||||
bool is_live,
|
||||
bool is_quoting);
|
||||
SpreaderChildOrderState (SpreaderChildOrderState&& src);
|
||||
SpreaderChildOrderState (SpreaderChildOrderState&& src);
|
||||
SpreaderChildOrderState& operator=(const SpreaderChildOrderState&) = delete;
|
||||
SpreaderChildOrderState& operator=(SpreaderChildOrderState&&) = delete;
|
||||
// const accessors ////////////////////
|
||||
///////////////////////////////////////
|
||||
SpreaderChildOrderState& operator=(SpreaderChildOrderState&&) = delete;
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// const direct accessors //////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
OrderKey order_key() const {
|
||||
if (_is_live)
|
||||
return _child_order.key();
|
||||
// TODO
|
||||
return _child_order.empty() ? OrderKey(0) : _child_order.key();
|
||||
else
|
||||
return _test_only_order_key;
|
||||
}
|
||||
api::orderman::OrderStatus status () const {
|
||||
}
|
||||
api::orderman::OrderStatus status() const {
|
||||
return _status;
|
||||
}
|
||||
// if the last fill was a status change
|
||||
// this will be zero
|
||||
Price last_update_filled_price() const {
|
||||
return _last_filled_price;
|
||||
// this is the fills from the current active order
|
||||
Quantity current_fills() const {
|
||||
return _filled_quantity;
|
||||
}
|
||||
Price last_reported_order_price() const{
|
||||
return _last_reported_order_price;
|
||||
Price last_update_filled_price() const {
|
||||
return _last_update_filled_price;
|
||||
}
|
||||
// if the last fill was a status change
|
||||
// this will be zero
|
||||
Quantity last_update_filled_quantity () const {
|
||||
return _last_filled_quantity;
|
||||
return _last_update_filled_quantity;
|
||||
}
|
||||
// all the status calls are based on the
|
||||
// current order (and not the subsumed ones)
|
||||
Price last_reported_order_price() const{
|
||||
return _last_reported_order_price;
|
||||
}
|
||||
Quantity last_reported_order_quantity() const{
|
||||
return _last_reported_order_qty;
|
||||
}
|
||||
Price out_price() const {
|
||||
return _out_price;
|
||||
}
|
||||
Quantity out_quantity () const {
|
||||
return _out_quantity;
|
||||
}
|
||||
bts::TimeStamp order_place_time() const{
|
||||
return _order_place_time;
|
||||
}
|
||||
// status accessors ////////////////////////////////////////////////////////
|
||||
bool terminal_status() const {
|
||||
return SpreaderUtils::order_in_terminal_state(_status);
|
||||
return SpreaderUtils::order_in_terminal_state(_status);
|
||||
}
|
||||
bool acknowledged() const {
|
||||
return SpreaderUtils::order_acknowledged (_status);
|
||||
@@ -100,8 +128,13 @@ public:
|
||||
bool errored() const{
|
||||
return SpreaderUtils::order_in_error_state(_status);
|
||||
}
|
||||
// this is total fills across current and
|
||||
// previous orders
|
||||
bool working() const{
|
||||
return SpreaderUtils::order_in_working_state(_status);
|
||||
}
|
||||
bool cancel_sent() const{
|
||||
return _n_cancel_orders > 0;
|
||||
}
|
||||
// total across multiple orders ////////////////////////////////////////////
|
||||
Quantity total_fills() const {
|
||||
return Quantity(_base_quantity.value() + _filled_quantity.value());
|
||||
}
|
||||
@@ -111,30 +144,29 @@ public:
|
||||
_filled_price, _filled_quantity,
|
||||
out_price, out_filled);
|
||||
}
|
||||
// this is the fills from the current active order
|
||||
Quantity current_fills () const {
|
||||
return _filled_quantity;
|
||||
}
|
||||
Price out_price() const {
|
||||
return _out_price;
|
||||
// returns true is there are no cancels
|
||||
// or modifies in flight
|
||||
bool stable_state() const{
|
||||
return !cancel_in_flight() && !_change_in_flight();
|
||||
}
|
||||
Quantity out_quantity () const {
|
||||
return _out_quantity;
|
||||
}
|
||||
bts::TimeStamp order_place_time() const{
|
||||
return _order_place_time;
|
||||
}
|
||||
// returns true if the current order has been
|
||||
// cancelled
|
||||
bool is_cancelled() const{
|
||||
return _n_cancel_orders>0;
|
||||
// in-flight accessors /////////////////////////////////////////////////////
|
||||
bool cancel_in_flight() const{
|
||||
return cancel_sent() && !terminal_status();
|
||||
}
|
||||
// init ///////////////////
|
||||
ChildOrder& active_order(){
|
||||
return _child_order;
|
||||
}
|
||||
void re_init (){
|
||||
ChildOrder empty_order;
|
||||
re_init(empty_order);
|
||||
}
|
||||
///////////////////////////
|
||||
// this assignes a new order, and subsumes the earlier order's
|
||||
// fills and filled price into the base quantity and
|
||||
// base filled price
|
||||
void re_init (ChildOrder& child_order);
|
||||
void re_init (ChildOrder& child_order,
|
||||
Quantity handover_filled_qty = Quantity(0));
|
||||
ChildOrder& _empty_order(){
|
||||
_child_order = ChildOrder();
|
||||
return _child_order;
|
||||
@@ -144,16 +176,20 @@ public:
|
||||
// last filled price
|
||||
void on_order_update(const OrderStateUpdateEvent& e){
|
||||
bts_assert(!_is_live || e.key == order_key());
|
||||
bts_assert(e.filled_quantity >= _filled_quantity.value());
|
||||
bts_assert(e.filled_quantity >= _handover_filled_qty.value());
|
||||
uint32_t effective_filled_qty = e.filled_quantity -
|
||||
_handover_filled_qty.value();
|
||||
bts_assert(effective_filled_qty >= _filled_quantity.value());
|
||||
_status = e.status;
|
||||
_last_filled_quantity = Quantity(e.filled_quantity
|
||||
_last_update_filled_quantity = Quantity(effective_filled_qty
|
||||
- _filled_quantity.value());
|
||||
_last_filled_price = Price(e.last_price);
|
||||
_last_reported_order_price=Price(e.price);
|
||||
_last_update_filled_price = Price(e.last_price);
|
||||
_last_reported_order_price = Price(e.price);
|
||||
_last_reported_order_qty = Quantity(e.quantity);
|
||||
SpreaderUtils::compute_average_price(_filled_price,
|
||||
_filled_quantity,
|
||||
_last_filled_price,
|
||||
_last_filled_quantity,
|
||||
_last_update_filled_price,
|
||||
_last_update_filled_quantity,
|
||||
_filled_price,
|
||||
_filled_quantity);
|
||||
}
|
||||
|
||||
@@ -181,9 +181,16 @@ public:
|
||||
return _hedger_manager.test_only_get_hedger_at(index);
|
||||
}
|
||||
SingleFillHedger& add_new_hedger(bts::Price hedge_price,
|
||||
bts::Quantity hedge_quantity){
|
||||
bts::Quantity hedge_quantity,
|
||||
bool quote_as_hedge){
|
||||
SingleFillHedger& rv = _hedger_manager.get_hedger();
|
||||
rv.init_hedger (hedge_price,hedge_quantity);
|
||||
ISpreaderManager::OrderTransfer* order_transfer = nullptr;
|
||||
ISpreaderManager::OrderTransfer order_transfer_arg;
|
||||
if(quote_as_hedge){
|
||||
order_transfer_arg.q_order = _quoter_child_order_state;
|
||||
order_transfer = &order_transfer_arg;
|
||||
}
|
||||
rv.init_hedger (hedge_price, hedge_quantity, order_transfer);
|
||||
return rv;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -114,6 +114,9 @@ public:
|
||||
static bool order_in_cancelled_state (bts::api::orderman::OrderStatus order_status){
|
||||
return order_status == api::orderman::OrderStatus::ORDER_STATUS_CANCELED;
|
||||
}
|
||||
static bool order_in_working_state(bts::api::orderman::OrderStatus order_status){
|
||||
return order_status == api::orderman::OrderStatus::ORDER_STATUS_WORKING;
|
||||
}
|
||||
////////////////////////////////////////////////////
|
||||
// market data /////////////////////////////////////
|
||||
////////////////////////////////////////////////////
|
||||
@@ -652,6 +655,24 @@ public:
|
||||
out_cum_qty);
|
||||
quantity = Quantity(std::min(quantity.value(),out_cum_qty.value()));
|
||||
}
|
||||
// given an order's filled and out qty, and the desired target
|
||||
// from now on, this function finds the adjusted qty of the order
|
||||
// example 1 : working order is 3/10, and we want to use
|
||||
// this working order to get 9 from here on, this function
|
||||
// will return 12, to make this 3/12, to allow for 9
|
||||
// fills.
|
||||
// example 2 : working order is 3/10, and we want 2 more fills,
|
||||
// it will output 5
|
||||
// increments are guarded by allow_inc
|
||||
static uint32_t adjust_qty_to_target (uint32_t filled_qty,
|
||||
uint32_t order_qty,
|
||||
uint32_t target,
|
||||
bool allow_inc){
|
||||
uint32_t rv = filled_qty + target;
|
||||
if (rv > order_qty && !allow_inc)
|
||||
rv = order_qty;
|
||||
return rv;
|
||||
}
|
||||
////////////////////////2 legged spreads
|
||||
// given a quoting target qty, finds the "driver" price
|
||||
// and qty, thats needed to hedge the quote. It also
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "lib/orderman/orderman_utils/orderman_common.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/hedger/hedger_states/HedgerState.h"
|
||||
#include "lib/orderman/actors/order_manager/ChildOrder.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/ISpreaderManager.h"
|
||||
|
||||
namespace bts {
|
||||
namespace trace {struct CorID;}
|
||||
@@ -22,7 +23,8 @@ public:
|
||||
virtual const std::string state_text () const = 0;
|
||||
// called once and only once, before any other calls.
|
||||
virtual void init (Price price,
|
||||
Quantity quantity) = 0;
|
||||
Quantity quantity,
|
||||
ISpreaderManager::OrderTransfer* order = nullptr) = 0;
|
||||
// called only when this hedger's order is updated
|
||||
virtual void on_order_update (const SpreaderChildOrderState& order_update) = 0;
|
||||
// called only when the security that the hedger is working on
|
||||
|
||||
+11
-2
@@ -9,12 +9,21 @@ void HedgerEndStateWorker::on_transition (){
|
||||
// this is to allow the hedger to be re-used.
|
||||
// the state is cleared and the hedger returns
|
||||
// to the start state, waiting for the init call
|
||||
if(!_hedger->_is_permenantly_cancelled)
|
||||
if(!_hedger->_is_permenantly_cancelled){
|
||||
Quantity rem_to_fill = _hedger->_price_quantity_state.remaining_to_fill();
|
||||
if(rem_to_fill.value() > 0)
|
||||
_hedger->_spreader.send_hedge_order(
|
||||
_hedger->_leg_property_data.leg_index(),
|
||||
_hedger->_child_order_state.out_price(),
|
||||
rem_to_fill,
|
||||
false);
|
||||
_hedger->transform_to_START();
|
||||
}
|
||||
}
|
||||
|
||||
void HedgerEndStateWorker::init (Price,
|
||||
Quantity){
|
||||
Quantity,
|
||||
ISpreaderManager::OrderTransfer*){
|
||||
bts_assert_msg (false, "HedgerEndStateWorker::init illegal operation");
|
||||
}
|
||||
void HedgerEndStateWorker::on_order_update(const SpreaderChildOrderState&){
|
||||
|
||||
+3
-1
@@ -23,7 +23,9 @@ public:
|
||||
void on_transition () override;
|
||||
HedgerState state () const override {return HedgerState::END;}
|
||||
const std::string state_text () const override {return "END";}
|
||||
void init (Price price,Quantity quantity) override;
|
||||
void init (Price price,
|
||||
Quantity quantity,
|
||||
ISpreaderManager::OrderTransfer* order = nullptr) override;
|
||||
void on_order_update (const SpreaderChildOrderState& order_update) override;
|
||||
void on_book (const bts::orderman::Book& book) override;
|
||||
void cancel() override;
|
||||
|
||||
+23
-3
@@ -14,11 +14,31 @@ void HedgerStartStateWorker::on_transition (){
|
||||
}
|
||||
|
||||
void HedgerStartStateWorker::init (Price price,
|
||||
Quantity quantity){
|
||||
Quantity quantity,
|
||||
ISpreaderManager::OrderTransfer* order_ptr){
|
||||
_hedger->_price_quantity_state.re_init(price,quantity);
|
||||
if(quantity.value() > 0){
|
||||
_hedger->_place_order (price, quantity);
|
||||
_hedger->transform_to_WAITING_FOR_FIRST_ACK ();
|
||||
if(order_ptr==nullptr){
|
||||
_hedger->_place_order (price, quantity);
|
||||
_hedger->transform_to_WAITING_FOR_FIRST_ACK ();
|
||||
}
|
||||
else{
|
||||
SpreaderChildOrderState& q_order = *(order_ptr->q_order);
|
||||
bts_assert(q_order.working());
|
||||
//bts_assert(q_order.active_order().is_active());
|
||||
uint32_t hedge_order_qty = SpreaderUtils::adjust_qty_to_target(
|
||||
q_order.current_fills().value(),
|
||||
q_order.out_quantity().value(),
|
||||
quantity.value(),
|
||||
true);
|
||||
ChildOrder& existing_order = q_order.active_order();
|
||||
_hedger->_child_order_state.re_init(existing_order,
|
||||
q_order.current_fills());
|
||||
_hedger->_modify_order (price, Quantity(hedge_order_qty));
|
||||
_hedger->transform_to_WORKING();
|
||||
// figure out how many have been filled
|
||||
// reinit the SCO and modify the price/qty
|
||||
}
|
||||
}
|
||||
}
|
||||
void HedgerStartStateWorker::on_order_update(const SpreaderChildOrderState&){
|
||||
|
||||
+3
-1
@@ -21,7 +21,9 @@ public:
|
||||
void on_transition () override;
|
||||
HedgerState state () const override {return HedgerState::START;}
|
||||
const std::string state_text () const override {return "START";}
|
||||
void init (Price price,Quantity quantity) override;
|
||||
void init (Price price,
|
||||
Quantity quantity,
|
||||
ISpreaderManager::OrderTransfer* order = nullptr) override;
|
||||
void on_order_update (const SpreaderChildOrderState& order_update) override;
|
||||
void on_book (const bts::orderman::Book& book) override;
|
||||
void cancel() override;
|
||||
|
||||
+7
-4
@@ -6,17 +6,20 @@ namespace bts{
|
||||
namespace orderman{
|
||||
|
||||
void HedgerWaitingForCancelAckStateWorker::init (Price,
|
||||
Quantity){
|
||||
Quantity,
|
||||
ISpreaderManager::OrderTransfer*){
|
||||
bts_assert_msg (false, "HedgerWaitingForCancelAckStateWorker::init "
|
||||
"illegal operation");
|
||||
}
|
||||
void HedgerWaitingForCancelAckStateWorker::on_order_update(const SpreaderChildOrderState& order_update){
|
||||
void HedgerWaitingForCancelAckStateWorker::on_order_update(
|
||||
const SpreaderChildOrderState& order_update){
|
||||
bts_assert (order_update.acknowledged());
|
||||
_hedger->_price_quantity_state.update_fill (order_update.last_update_filled_quantity());
|
||||
_hedger->_price_quantity_state.update_fill (
|
||||
order_update.last_update_filled_quantity());
|
||||
if (order_update.terminal_status())
|
||||
_hedger->transform_to_END ();
|
||||
}
|
||||
void HedgerWaitingForCancelAckStateWorker::on_book(const bts::orderman::Book&){
|
||||
void HedgerWaitingForCancelAckStateWorker::on_book(const bts::orderman::Book&){
|
||||
}
|
||||
void HedgerWaitingForCancelAckStateWorker::cancel(){
|
||||
}
|
||||
|
||||
+3
-1
@@ -25,7 +25,9 @@ public:
|
||||
const std::string state_text () const override {
|
||||
return "WAITING_FOR_CANCEL_ACK";
|
||||
}
|
||||
void init (Price price,Quantity quantity) override;
|
||||
void init (Price price,
|
||||
Quantity quantity,
|
||||
ISpreaderManager::OrderTransfer* order = nullptr) override;
|
||||
void on_order_update (const SpreaderChildOrderState& order_update) override;
|
||||
void on_book (const bts::orderman::Book& book) override;
|
||||
void cancel() override;
|
||||
|
||||
+4
-3
@@ -8,7 +8,8 @@ namespace orderman{
|
||||
|
||||
void HedgerWaitingForFirstAckCancelledStateWorker::init(
|
||||
Price,
|
||||
Quantity){
|
||||
Quantity,
|
||||
ISpreaderManager::OrderTransfer*){
|
||||
bts_assert_msg (false, "HedgerWaitingForFirstAckCancelledStateWorker::init "
|
||||
"illegal operation");
|
||||
}
|
||||
@@ -26,8 +27,8 @@ void HedgerWaitingForFirstAckCancelledStateWorker::on_order_update(
|
||||
_hedger->transform_to_WAITING_FOR_CANCEL_ACK ();
|
||||
}
|
||||
}
|
||||
void HedgerWaitingForFirstAckCancelledStateWorker::on_book(const bts::orderman::Book&){
|
||||
|
||||
void HedgerWaitingForFirstAckCancelledStateWorker::on_book(
|
||||
const bts::orderman::Book&){
|
||||
}
|
||||
void HedgerWaitingForFirstAckCancelledStateWorker::cancel(){
|
||||
}
|
||||
|
||||
+3
-1
@@ -25,7 +25,9 @@ public:
|
||||
const std::string state_text () const override {
|
||||
return "WAITING_FOR_FIRST_ACK_CANCELLED";
|
||||
}
|
||||
void init (Price price,Quantity quantity) override;
|
||||
void init (Price price,
|
||||
Quantity quantity,
|
||||
ISpreaderManager::OrderTransfer* order = nullptr) override;
|
||||
void on_order_update (const SpreaderChildOrderState& order_update) override;
|
||||
void on_book (const bts::orderman::Book& book) override;
|
||||
void cancel() override;
|
||||
|
||||
+2
-1
@@ -5,7 +5,8 @@ namespace bts{
|
||||
namespace orderman{
|
||||
|
||||
void HedgerWaitingForFirstAckStateWorker::init (Price,
|
||||
Quantity){
|
||||
Quantity,
|
||||
ISpreaderManager::OrderTransfer*){
|
||||
bts_assert_msg (false, "HedgerWaitingForFirstAckStateWorker::init "
|
||||
"illegal operation");
|
||||
}
|
||||
|
||||
+3
-1
@@ -26,7 +26,9 @@ public:
|
||||
const std::string state_text () const override {
|
||||
return "WAITING_FOR_FIRST_ACK";
|
||||
}
|
||||
void init (Price price,Quantity quantity) override;
|
||||
void init (Price price,
|
||||
Quantity quantity,
|
||||
ISpreaderManager::OrderTransfer* order = nullptr) override;
|
||||
void on_order_update (const SpreaderChildOrderState& order_update) override;
|
||||
void on_book (const bts::orderman::Book& book) override;
|
||||
void cancel() override;
|
||||
|
||||
+10
-6
@@ -10,7 +10,8 @@ void HedgerWorkingStateWorker::on_transition(){
|
||||
_order_touch_time = _hedger->_current_time();
|
||||
}
|
||||
void HedgerWorkingStateWorker::init(Price,
|
||||
Quantity){
|
||||
Quantity,
|
||||
ISpreaderManager::OrderTransfer*){
|
||||
bts_assert_msg (false, "HedgerWorkingStateWorker::init illegal operation");
|
||||
}
|
||||
void HedgerWorkingStateWorker::on_order_update(
|
||||
@@ -42,12 +43,15 @@ void HedgerWorkingStateWorker::terminate(){
|
||||
}
|
||||
void HedgerWorkingStateWorker::on_time(const TimeStamp& ts){
|
||||
double new_price;
|
||||
const auto& book =
|
||||
_hedger->_spreader.get_book (_hedger->_leg_property_data.leg_index());
|
||||
if (SpreaderUtils::post_hedge_time_based_price_action (
|
||||
_order_touch_time,
|
||||
ts,
|
||||
_hedger->_leg_property_data,
|
||||
_hedger->_spreader.get_book (_hedger->_leg_property_data.leg_index()),
|
||||
new_price)){
|
||||
_order_touch_time,
|
||||
ts,
|
||||
_hedger->_leg_property_data,
|
||||
book,
|
||||
new_price))
|
||||
{
|
||||
_hedger->_modify_order (Price(new_price));
|
||||
_order_touch_time = _hedger->_current_time();
|
||||
}
|
||||
|
||||
+3
-1
@@ -23,7 +23,9 @@ public:
|
||||
void on_transition () override;
|
||||
HedgerState state () const override {return HedgerState::WORKING;}
|
||||
const std::string state_text () const override {return "WORKING";}
|
||||
void init (Price price,Quantity quantity) override;
|
||||
void init (Price price,
|
||||
Quantity quantity,
|
||||
ISpreaderManager::OrderTransfer* order = nullptr) override;
|
||||
void on_order_update (const SpreaderChildOrderState& order_update) override;
|
||||
void on_book (const bts::orderman::Book& book) override;
|
||||
void cancel() override;
|
||||
|
||||
@@ -35,7 +35,10 @@ public:
|
||||
// time update from the infrastructure
|
||||
virtual void on_time(const TimeStamp&) = 0;
|
||||
// on a quoting fill on one of the other legs
|
||||
virtual void on_other_leg_quoter_fill (size_t leg_id, Quantity fill_quantity) = 0;
|
||||
virtual void on_other_leg_quoter_fill (size_t leg_id,
|
||||
Quantity fill_quantity,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty) = 0;
|
||||
// when a spreader order gets updated, it could be that the one of
|
||||
// the price or quantity does not change
|
||||
virtual void update_spreader_order (Price price, Quantity quantity) = 0;
|
||||
|
||||
+6
-3
@@ -18,7 +18,8 @@ void QuoterEndStateWorker::on_transition (){
|
||||
_quoter->irrecoverable_error();
|
||||
if (!is_final){
|
||||
// getting new order
|
||||
_quoter->_spreader.setup_new_quoter_order(_quoter->_this_leg_data.leg_index());
|
||||
_quoter->_spreader.setup_new_quoter_order(
|
||||
_quoter->_this_leg_data.leg_index());
|
||||
_quoter->_transform_to_WAITING_FOR_SIZE ();
|
||||
}
|
||||
}
|
||||
@@ -37,8 +38,10 @@ void QuoterEndStateWorker::terminate()
|
||||
{}
|
||||
void QuoterEndStateWorker::on_time(const TimeStamp&)
|
||||
{}
|
||||
void QuoterEndStateWorker::on_other_leg_quoter_fill (size_t, Quantity)
|
||||
{}
|
||||
void QuoterEndStateWorker::on_other_leg_quoter_fill (size_t,
|
||||
Quantity,
|
||||
Price,
|
||||
Quantity){}
|
||||
void QuoterEndStateWorker::update_spreader_order (Price, Quantity)
|
||||
{}
|
||||
}}
|
||||
+4
-1
@@ -29,7 +29,10 @@ public:
|
||||
void cancel() override;
|
||||
void terminate() override;
|
||||
void on_time(const TimeStamp& ts) override;
|
||||
void on_other_leg_quoter_fill (size_t leg_id, Quantity fill_quantity) override;
|
||||
void on_other_leg_quoter_fill (size_t leg_id,
|
||||
Quantity fill_quantity,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty) override;
|
||||
void update_spreader_order (Price price, Quantity quantity) override;
|
||||
};
|
||||
}}
|
||||
+5
-2
@@ -43,8 +43,11 @@ void QuoterStartStateWorker::on_time(const TimeStamp&){
|
||||
// however for the purpose of this state, we can hide that detail and deal
|
||||
// with it all !
|
||||
void QuoterStartStateWorker::on_other_leg_quoter_fill (size_t leg_index,
|
||||
Quantity filled_quantity){
|
||||
_quoter->_incorporate_other_leg_fill (leg_index, filled_quantity);
|
||||
Quantity filled_quantity,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty){
|
||||
_quoter->_incorporate_other_leg_fill (leg_index, filled_quantity,
|
||||
hedge_price, hedge_qty);
|
||||
}
|
||||
// same as above, but we can deal with it like one_time_activate
|
||||
void QuoterStartStateWorker::update_spreader_order (Price price, Quantity quantity){
|
||||
|
||||
+4
-1
@@ -27,7 +27,10 @@ public:
|
||||
void cancel() override;
|
||||
void terminate() override;
|
||||
void on_time(const TimeStamp& ts) override;
|
||||
void on_other_leg_quoter_fill (size_t leg_id, Quantity fill_quantity) override;
|
||||
void on_other_leg_quoter_fill (size_t leg_id,
|
||||
Quantity fill_quantity,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty) override;
|
||||
void update_spreader_order (Price price, Quantity quantity) override;
|
||||
};
|
||||
}}
|
||||
@@ -10,6 +10,7 @@ enum class QuoterState
|
||||
WAITING_FOR_IOC,
|
||||
WAITING_FOR_FIRST_ACK_CANCELLED,
|
||||
WORKING,
|
||||
WAITING_FOR_ORDER_TRANSFER,
|
||||
WAITING_FOR_CANCEL_ACK,
|
||||
END
|
||||
};
|
||||
|
||||
+7
-3
@@ -30,9 +30,13 @@ void QuoterWaitingForCancelAckStateWorker::terminate(){
|
||||
void QuoterWaitingForCancelAckStateWorker::on_time(const TimeStamp&){
|
||||
// TODO check threshold
|
||||
}
|
||||
void QuoterWaitingForCancelAckStateWorker::on_other_leg_quoter_fill (size_t leg_index,
|
||||
Quantity filled_quantity){
|
||||
_quoter->_incorporate_other_leg_fill (leg_index, filled_quantity);
|
||||
void QuoterWaitingForCancelAckStateWorker::on_other_leg_quoter_fill (
|
||||
size_t leg_index,
|
||||
Quantity filled_quantity,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty){
|
||||
_quoter->_incorporate_other_leg_fill (leg_index, filled_quantity,
|
||||
hedge_price, hedge_qty);
|
||||
}
|
||||
void QuoterWaitingForCancelAckStateWorker::update_spreader_order (Price price,
|
||||
Quantity quantity){
|
||||
|
||||
+4
-1
@@ -28,7 +28,10 @@ public:
|
||||
void cancel() override;
|
||||
void terminate() override;
|
||||
void on_time(const TimeStamp& ts) override;
|
||||
void on_other_leg_quoter_fill (size_t leg_id, Quantity fill_quantity) override;
|
||||
void on_other_leg_quoter_fill (size_t leg_id,
|
||||
Quantity fill_quantity,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty) override;
|
||||
void update_spreader_order (Price price, Quantity quantity) override;
|
||||
};
|
||||
}}
|
||||
+7
-2
@@ -34,8 +34,13 @@ void QuoterWaitingForFirstAckCancelledWorker::terminate(){
|
||||
}
|
||||
void QuoterWaitingForFirstAckCancelledWorker::on_time(const TimeStamp&){
|
||||
}
|
||||
void QuoterWaitingForFirstAckCancelledWorker::on_other_leg_quoter_fill (size_t leg_index, Quantity filled_quantity){
|
||||
_quoter->_incorporate_other_leg_fill (leg_index, filled_quantity);
|
||||
void QuoterWaitingForFirstAckCancelledWorker::on_other_leg_quoter_fill (
|
||||
size_t leg_index,
|
||||
Quantity filled_quantity,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty){
|
||||
_quoter->_incorporate_other_leg_fill (leg_index, filled_quantity,
|
||||
hedge_price, hedge_qty);
|
||||
}
|
||||
void QuoterWaitingForFirstAckCancelledWorker::update_spreader_order (Price price,
|
||||
Quantity quantity){
|
||||
|
||||
+4
-1
@@ -34,7 +34,10 @@ public:
|
||||
void cancel() override;
|
||||
void terminate() override;
|
||||
void on_time(const TimeStamp& ts) override;
|
||||
void on_other_leg_quoter_fill (size_t leg_id, Quantity fill_quantity) override;
|
||||
void on_other_leg_quoter_fill (size_t leg_id,
|
||||
Quantity fill_quantity,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty) override;
|
||||
void update_spreader_order (Price price, Quantity quantity) override;
|
||||
};
|
||||
}}
|
||||
+5
-2
@@ -34,8 +34,11 @@ void QuoterWaitingForFirstAckWorker::terminate(){
|
||||
void QuoterWaitingForFirstAckWorker::on_time(const TimeStamp&){
|
||||
}
|
||||
void QuoterWaitingForFirstAckWorker::on_other_leg_quoter_fill (size_t leg_index,
|
||||
Quantity filled_quantity){
|
||||
_quoter->_incorporate_other_leg_fill (leg_index, filled_quantity);
|
||||
Quantity filled_quantity,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty){
|
||||
_quoter->_incorporate_other_leg_fill (leg_index, filled_quantity,
|
||||
hedge_price, hedge_qty);
|
||||
_analyze_and_act ();
|
||||
}
|
||||
void QuoterWaitingForFirstAckWorker::update_spreader_order (Price price,
|
||||
|
||||
+4
-1
@@ -32,7 +32,10 @@ public:
|
||||
void cancel() override;
|
||||
void terminate() override;
|
||||
void on_time(const TimeStamp& ts) override;
|
||||
void on_other_leg_quoter_fill (size_t leg_id, Quantity fill_quantity) override;
|
||||
void on_other_leg_quoter_fill (size_t leg_id,
|
||||
Quantity fill_quantity,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty) override;
|
||||
void update_spreader_order (Price price, Quantity quantity) override;
|
||||
private:
|
||||
// checks if the target is reached, and cancels
|
||||
|
||||
+7
-3
@@ -34,9 +34,13 @@ void QuoterWaitingForIOCWorker::terminate(){
|
||||
}
|
||||
void QuoterWaitingForIOCWorker::on_time(const TimeStamp&){
|
||||
}
|
||||
void QuoterWaitingForIOCWorker::on_other_leg_quoter_fill (size_t leg_index,
|
||||
Quantity filled_quantity){
|
||||
_quoter->_incorporate_other_leg_fill (leg_index, filled_quantity);
|
||||
void QuoterWaitingForIOCWorker::on_other_leg_quoter_fill (
|
||||
size_t leg_index,
|
||||
Quantity filled_quantity,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty){
|
||||
_quoter->_incorporate_other_leg_fill (leg_index, filled_quantity,
|
||||
hedge_price, hedge_qty);
|
||||
}
|
||||
void QuoterWaitingForIOCWorker::update_spreader_order (Price price,
|
||||
Quantity quantity){
|
||||
|
||||
+4
-1
@@ -35,7 +35,10 @@ public:
|
||||
void cancel() override;
|
||||
void terminate() override;
|
||||
void on_time(const TimeStamp& ts) override;
|
||||
void on_other_leg_quoter_fill (size_t leg_id, Quantity fill_quantity) override;
|
||||
void on_other_leg_quoter_fill (size_t leg_id,
|
||||
Quantity fill_quantity,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty) override;
|
||||
void update_spreader_order (Price price, Quantity quantity) override;
|
||||
};
|
||||
}}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/SpreaderChildOrderState.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWaitingForOrderTransferStateWorker.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterState.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/SingleLegQuoter.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/SpreaderChildOrderState.h"
|
||||
|
||||
namespace bts{
|
||||
namespace orderman{
|
||||
|
||||
QuoterState QuoterWaitingForOrderTransferStateWorker::state () const {
|
||||
return QuoterState::WAITING_FOR_ORDER_TRANSFER;
|
||||
}
|
||||
void QuoterWaitingForOrderTransferStateWorker::one_time_activate (Price,
|
||||
Quantity){
|
||||
bts_assert_msg (false,
|
||||
"QuoterWaitingForOrderTransferStateWorker::one_time_activate "
|
||||
"is an illegal operation");
|
||||
}
|
||||
void QuoterWaitingForOrderTransferStateWorker::on_order_update (
|
||||
const SpreaderChildOrderState& u){
|
||||
bts_assert (u.acknowledged());
|
||||
_analyze_and_act();
|
||||
}
|
||||
void QuoterWaitingForOrderTransferStateWorker::on_book (
|
||||
size_t,
|
||||
const bts::orderman::Book&){
|
||||
}
|
||||
void QuoterWaitingForOrderTransferStateWorker::cancel(){
|
||||
_quoter->_cancel_order();
|
||||
_quoter->_transform_to_WAITING_FOR_CANCEL_ACK ();
|
||||
}
|
||||
void QuoterWaitingForOrderTransferStateWorker::terminate(){
|
||||
_quoter->_transform_to_END ();
|
||||
}
|
||||
void QuoterWaitingForOrderTransferStateWorker::on_time(const TimeStamp&){
|
||||
}
|
||||
void QuoterWaitingForOrderTransferStateWorker::on_other_leg_quoter_fill (
|
||||
size_t leg_index,
|
||||
Quantity filled_quantity,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty){
|
||||
_quoter->_incorporate_other_leg_fill (leg_index, filled_quantity,
|
||||
hedge_price, hedge_qty);
|
||||
_analyze_and_act();
|
||||
}
|
||||
void QuoterWaitingForOrderTransferStateWorker::update_spreader_order (
|
||||
Price price,
|
||||
Quantity quantity){
|
||||
_quoter->_price_quantity_state.update_target_price_quantity (price, quantity);
|
||||
_analyze_and_act();
|
||||
}
|
||||
void QuoterWaitingForOrderTransferStateWorker::_analyze_and_act(){
|
||||
const auto& u = _quoter->_child_order_state;
|
||||
if(u.terminal_status() ||
|
||||
_quoter->_price_quantity_state.target_reached()){
|
||||
_quoter->_transform_to_END ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "lib/orderman/orderman_utils/orderman_common.h"
|
||||
#include "lib/utils/bts_chrono.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterState.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/quoter/IQuoterStateWorker.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
class SpreaderChildOrderState;
|
||||
class Book;
|
||||
class SingleLegQuoter;
|
||||
// Quoter order is in the process of transferring ownership
|
||||
// to thehedger
|
||||
// exit:
|
||||
class QuoterWaitingForOrderTransferStateWorker : public IQuoterStateWorker
|
||||
{
|
||||
private:
|
||||
SingleLegQuoter* const _quoter;
|
||||
public:
|
||||
QuoterWaitingForOrderTransferStateWorker (SingleLegQuoter* quoter)
|
||||
:_quoter(quoter){}
|
||||
QuoterState state () const override;
|
||||
const std::string state_text () const override {
|
||||
return "WAITING_FOR_ORDER_TRANSFER";
|
||||
}
|
||||
virtual void on_transition () override {}
|
||||
void one_time_activate (Price, Quantity) override;
|
||||
void on_order_update (
|
||||
const SpreaderChildOrderState& order_update) override;
|
||||
void on_book (size_t leg_id, const bts::orderman::Book& book) override;
|
||||
void cancel() override;
|
||||
void terminate() override;
|
||||
void on_time(const TimeStamp& ts) override;
|
||||
void on_other_leg_quoter_fill (size_t leg_id,
|
||||
Quantity fill_quantity,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty) override;
|
||||
void update_spreader_order (Price price, Quantity quantity) override;
|
||||
private:
|
||||
void _analyze_and_act ();
|
||||
};
|
||||
}}
|
||||
+5
-2
@@ -34,8 +34,11 @@ void QuoterWaitingForSizeStateWorker::on_time(const TimeStamp&){
|
||||
}
|
||||
|
||||
void QuoterWaitingForSizeStateWorker::on_other_leg_quoter_fill (size_t leg_index,
|
||||
Quantity filled_quantity){
|
||||
_quoter->_incorporate_other_leg_fill (leg_index, filled_quantity);
|
||||
Quantity filled_quantity,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty){
|
||||
_quoter->_incorporate_other_leg_fill (leg_index, filled_quantity,
|
||||
hedge_price, hedge_qty);
|
||||
_longpath_analyze_and_act ();
|
||||
}
|
||||
void QuoterWaitingForSizeStateWorker::update_spreader_order (Price price,
|
||||
|
||||
+4
-1
@@ -34,7 +34,10 @@ public:
|
||||
void cancel() override;
|
||||
void terminate() override;
|
||||
void on_time(const TimeStamp& ts) override;
|
||||
void on_other_leg_quoter_fill (size_t leg_id, Quantity fill_quantity) override;
|
||||
void on_other_leg_quoter_fill (size_t leg_id,
|
||||
Quantity fill_quantity,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty) override;
|
||||
void update_spreader_order (Price price, Quantity quantity) override;
|
||||
private:
|
||||
// checks to see if target has reached and goes to end
|
||||
|
||||
+69
-5
@@ -5,6 +5,7 @@
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/ISpreaderManager.h"
|
||||
#include "lib/orderman/orderman_utils/orderman_common.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/SpreaderCacheWarmingState.h"
|
||||
#include "lib/domain_model/Security.h"
|
||||
|
||||
namespace bts{
|
||||
namespace orderman{
|
||||
@@ -41,12 +42,28 @@ void QuoterWorkingStateWorker::cancel(){
|
||||
void QuoterWorkingStateWorker::terminate(){
|
||||
_quoter->_transform_to_END ();
|
||||
}
|
||||
void QuoterWorkingStateWorker::on_time(const TimeStamp&){
|
||||
void QuoterWorkingStateWorker::on_time(const TimeStamp&){
|
||||
}
|
||||
void QuoterWorkingStateWorker::on_other_leg_quoter_fill (size_t leg_index,
|
||||
Quantity filled_quantity){
|
||||
_quoter->_incorporate_other_leg_fill (leg_index, filled_quantity);
|
||||
_longpath_analyze_and_act ();
|
||||
void QuoterWorkingStateWorker::on_other_leg_quoter_fill (
|
||||
size_t leg_index,
|
||||
Quantity filled_quantity,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty){
|
||||
bool q_to_h = hedge_qty.value() > 0 &&
|
||||
_use_quoting_order_to_hedge(hedge_price,hedge_qty);
|
||||
// decide how to send hedge
|
||||
_quoter->_incorporate_other_leg_fill (leg_index,
|
||||
filled_quantity,
|
||||
hedge_price,
|
||||
hedge_qty,
|
||||
true,
|
||||
q_to_h);
|
||||
if(q_to_h){
|
||||
_quoter->_child_order_state.re_init();
|
||||
_quoter->_transform_to_END();
|
||||
}
|
||||
else
|
||||
_longpath_analyze_and_act ();
|
||||
}
|
||||
void QuoterWorkingStateWorker::update_spreader_order (Price price,
|
||||
Quantity quantity){
|
||||
@@ -99,4 +116,51 @@ void QuoterWorkingStateWorker::_modify_order (Price price, Quantity quantity){
|
||||
_quoter->_modify_order(price, quantity);
|
||||
}
|
||||
}
|
||||
bool QuoterWorkingStateWorker::_use_quoting_order_to_hedge(Price h_price,
|
||||
Quantity h_qty) const{
|
||||
const LegPropertyData& leg = _quoter->_this_leg_data;
|
||||
const SpreaderChildOrderState& q_ord = _quoter->_child_order_state;
|
||||
// check to see if the order is in transition ?
|
||||
auto q_for_h = leg.use_quote_for_hedging();
|
||||
bool q_better = securities::same_or_better_order_price(
|
||||
_quoter->_this_leg_data.trading_side(),
|
||||
q_ord.last_reported_order_price(),
|
||||
h_price) &&
|
||||
// this is to make sure that the hedge price
|
||||
// is also worse than anything in flight
|
||||
securities::same_or_better_order_price(
|
||||
_quoter->_this_leg_data.trading_side(),
|
||||
q_ord.out_price(),
|
||||
h_price);
|
||||
bool rv;
|
||||
switch(q_for_h){
|
||||
case spark::UseSpreaderQuoteForHedging::NEVER:
|
||||
rv = false;
|
||||
break;
|
||||
case spark::UseSpreaderQuoteForHedging::WHEN_CANT_OVERHEDGE:
|
||||
rv = q_better &&
|
||||
// max fill potential <= hedge qty
|
||||
h_qty.value() >= SpreaderUtils::subtract_quanitities(
|
||||
q_ord.out_quantity().value(),
|
||||
q_ord.current_fills().value()) &&
|
||||
h_qty.value() >= SpreaderUtils::subtract_quanitities(
|
||||
q_ord.last_reported_order_quantity().value(),
|
||||
q_ord.current_fills().value());
|
||||
break;
|
||||
case spark::UseSpreaderQuoteForHedging::ALWAYS:
|
||||
rv = q_better;
|
||||
break;
|
||||
default:
|
||||
bts_assert(false);
|
||||
rv = false;
|
||||
break;
|
||||
}
|
||||
LOG(OrderMan, Info, "QuoterWorkingStateWorker::_use_quoting_order_to_hedge "
|
||||
"res: leg:{} hp:{} hq:{}",
|
||||
rv,
|
||||
leg.leg_index(),
|
||||
h_price,
|
||||
h_qty);
|
||||
return rv;
|
||||
}
|
||||
}}
|
||||
+6
-1
@@ -27,7 +27,10 @@ public:
|
||||
void cancel() override;
|
||||
void terminate() override;
|
||||
void on_time(const TimeStamp& ts) override;
|
||||
void on_other_leg_quoter_fill (size_t leg_id, Quantity fill_quantity) override;
|
||||
void on_other_leg_quoter_fill (size_t leg_id,
|
||||
Quantity fill_quantity,
|
||||
Price hedge_price,
|
||||
Quantity hedge_qty) override;
|
||||
void update_spreader_order (Price price, Quantity quantity) override;
|
||||
private:
|
||||
// this does the following in this order
|
||||
@@ -36,5 +39,7 @@ private:
|
||||
// iii. if reprice (ie qty changed or price changed beyond the threshold) => requote
|
||||
void _longpath_analyze_and_act ();
|
||||
void _modify_order (Price price, Quantity quantity);
|
||||
bool _use_quoting_order_to_hedge(Price h_price,
|
||||
Quantity h_qty) const;
|
||||
};
|
||||
}}
|
||||
+14
-6
@@ -123,17 +123,25 @@ void SpreaderWorkingStateWorker::on_quoter_order_fill(SpreaderLegData& leg_data)
|
||||
LOG(OrderMan,cw.llevel,"h_p delta {} {}", q_idx, _spreader->_diff_ns());
|
||||
// if it is an actively quoting leg, inform the quoter about it
|
||||
// so it can decrease the proportional size
|
||||
if (!cw.in_cache_warming_cycle &&
|
||||
other_leg_data.leg_property_data().is_active_quoting()){
|
||||
// if (!cw.in_cache_warming_cycle &&
|
||||
// other_leg_data.leg_property_data().is_active_quoting()){
|
||||
// if this leg is an active quoting leg, let it deal with
|
||||
// hedging since it can use its own order to hedge
|
||||
if (other_leg_data.leg_property_data().is_active_quoting()){
|
||||
other_leg_data.quoter().update_other_leg_fills(
|
||||
leg_data.leg_property_data().leg_index(),
|
||||
Quantity(total_unhedged_qty),
|
||||
hedge_price,
|
||||
Quantity(total_unhedged_qty));
|
||||
LOG(OrderMan,cw.llevel,"h_p q minus {} {}", q_idx, _spreader->_diff_ns());
|
||||
}
|
||||
// a hedge is sent regardless
|
||||
_spreader->_send_hedge(other_leg_data.leg_property_data().leg_index(),
|
||||
hedge_price,
|
||||
Quantity(total_unhedged_qty));
|
||||
else
|
||||
// if it is not a quoting leg, the hedge needs to be
|
||||
// sent explictely from here
|
||||
_spreader->_send_hedge(other_leg_data.leg_property_data().leg_index(),
|
||||
hedge_price,
|
||||
Quantity(total_unhedged_qty),
|
||||
false);
|
||||
LOG(OrderMan,cw.llevel,"h_p send hedge {} {}", q_idx, _spreader->_diff_ns());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,6 +90,11 @@ public:
|
||||
ChildOrder rv;
|
||||
return rv;
|
||||
}
|
||||
void send_hedge_order (size_t,
|
||||
Price,
|
||||
Quantity,
|
||||
bool){
|
||||
}
|
||||
bool in_cache_warming_cycle() const override{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,12 @@ message RulePriority
|
||||
int32 priority = 20;
|
||||
}
|
||||
|
||||
enum UseSpreaderQuoteForHedging
|
||||
{
|
||||
NEVER = 0;
|
||||
WHEN_CANT_OVERHEDGE = 1;
|
||||
ALWAYS = 2;
|
||||
}
|
||||
|
||||
message LegSpreaderParams
|
||||
{
|
||||
@@ -46,7 +52,7 @@ message LegSpreaderParams
|
||||
PreHedgeParams pre_hedge_params = 50;
|
||||
PostHedgeParams post_hedge_params = 60;
|
||||
MarketDataType market_data_type = 70;
|
||||
//reserve LegMarketDataCalculation leg_md_calc = 80;
|
||||
//reserve LegMarketDataCalculation leg_md_calc = 80;
|
||||
}
|
||||
|
||||
// /*************************************************************************************************
|
||||
@@ -74,7 +80,8 @@ message QuoteParams
|
||||
// and the user can embed a QHO here)
|
||||
uint32 n_queue_holder_orders=2000;
|
||||
// this is the show quantity on the quoter order
|
||||
NullableQuantity show_quantity = 2010;
|
||||
NullableQuantity show_quantity = 2010;
|
||||
UseSpreaderQuoteForHedging use_quote_for_hedging = 2020;
|
||||
}
|
||||
|
||||
/*************************************Quote MuteZone***********************************
|
||||
|
||||
Reference in new issue
Block a user