Compare commits

...
53 changed files with 592 additions and 156 deletions

No files matched your search

+3 -3
View File
@@ -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": {
+1 -1
View File
@@ -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*/
+8
View File
@@ -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
@@ -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&){
@@ -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;
@@ -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&){
@@ -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;
@@ -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(){
}
@@ -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;
@@ -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(){
}
@@ -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;
@@ -5,7 +5,8 @@ namespace bts{
namespace orderman{
void HedgerWaitingForFirstAckStateWorker::init (Price,
Quantity){
Quantity,
ISpreaderManager::OrderTransfer*){
bts_assert_msg (false, "HedgerWaitingForFirstAckStateWorker::init "
"illegal operation");
}
@@ -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,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();
}
@@ -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;
@@ -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)
{}
}}
@@ -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;
};
}}
@@ -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){
@@ -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
};
@@ -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){
@@ -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;
};
}}
@@ -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){
@@ -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;
};
}}
@@ -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,
@@ -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
@@ -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){
@@ -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;
};
}}
@@ -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;
}
}
}}
@@ -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 ();
};
}}
@@ -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,
@@ -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
@@ -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;
}
}}
@@ -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;
};
}}
@@ -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;
}
+9 -2
View File
@@ -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***********************************