Use a better exit slot heuristic
When exiting a pp toward net-zero, we may sometimes run into the issue of having a "fractional slot" worth of units in allocator limit terms. This is further nuanced by live orders which are submitted above the current clearing price which get allocated a size (based on that staged but non-cleared price) according to their limit size unit which can be calculated to be less then the size that would have been allocated at the actual clearing price. In the short term cope with this discrepancy by simply using a "slot and a half" as the decision point of whether to exit a slot's worth or the remaining pp's worth of units. In other words if you can exit 1.5x a slot's worth or less, exit the remaining pp, otherwise exit a slot's worth. This is a stop gap until we have a better solution to limiting staged orders to (some range around) the currently computed clear-able price.fsp_feeds
parent
03c38a1163
commit
abc5c382ae
|
@ -147,17 +147,18 @@ class Allocator(BaseModel):
|
||||||
sym = self.symbol
|
sym = self.symbol
|
||||||
ld = sym.lot_size_digits
|
ld = sym.lot_size_digits
|
||||||
|
|
||||||
|
size_unit = self.size_unit
|
||||||
live_size = live_pp.size
|
live_size = live_pp.size
|
||||||
abs_live_size = abs(live_size)
|
abs_live_size = abs(live_size)
|
||||||
abs_startup_size = abs(startup_pp.size)
|
abs_startup_size = abs(startup_pp.size)
|
||||||
|
|
||||||
u_per_slot, currency_per_slot = self.step_sizes()
|
u_per_slot, currency_per_slot = self.step_sizes()
|
||||||
|
|
||||||
if self.size_unit == 'units':
|
if size_unit == 'units':
|
||||||
enter_step = u_per_slot
|
enter_step = u_per_slot
|
||||||
l_sub_pp = self.units_limit - abs_live_size
|
l_sub_pp = self.units_limit - abs_live_size
|
||||||
|
|
||||||
elif self.size_unit == 'currency':
|
elif size_unit == 'currency':
|
||||||
live_cost_basis = abs_live_size * live_pp.avg_price
|
live_cost_basis = abs_live_size * live_pp.avg_price
|
||||||
enter_step = currency_per_slot / price
|
enter_step = currency_per_slot / price
|
||||||
l_sub_pp = (self.currency_limit - live_cost_basis) / price
|
l_sub_pp = (self.currency_limit - live_cost_basis) / price
|
||||||
|
@ -173,26 +174,41 @@ class Allocator(BaseModel):
|
||||||
|
|
||||||
# an exit (removing-from or going to net-zero pp)
|
# an exit (removing-from or going to net-zero pp)
|
||||||
else:
|
else:
|
||||||
# when exiting a pp we always slot the position
|
# when exiting a pp we always try to slot the position
|
||||||
# in the instrument's units, since doing so in a derived
|
# in the instrument's units, since doing so in a derived
|
||||||
# size measure (eg. currency value, percent of port) would
|
# size measure (eg. currency value, percent of port) would
|
||||||
# result in a mis-mapping of slots sizes in unit terms
|
# result in a mis-mapping of slots sizes in unit terms
|
||||||
# (i.e. it would take *more* slots to exit at a profit and
|
# (i.e. it would take *more* slots to exit at a profit and
|
||||||
# *less* slots to exit at a loss).
|
# *less* slots to exit at a loss).
|
||||||
slot_size = abs_startup_size / self.slots
|
pp_size = max(abs_startup_size, abs_live_size)
|
||||||
|
slotted_pp = pp_size / self.slots
|
||||||
|
|
||||||
|
if size_unit == 'currency':
|
||||||
|
# compute the "projected" limit's worth of units at the
|
||||||
|
# current pp (weighted) price:
|
||||||
|
slot_size = currency_per_slot / live_pp.avg_price
|
||||||
|
|
||||||
|
else:
|
||||||
|
slot_size = u_per_slot
|
||||||
|
|
||||||
|
# if our position is greater then our limit setting
|
||||||
|
# we'll want to use slot sizes which are larger then what
|
||||||
|
# the limit would normally determine
|
||||||
|
order_size = max(slotted_pp, slot_size)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
abs_live_size < slot_size or
|
abs_live_size < slot_size or
|
||||||
slot_size < abs_live_size < (2*slot_size)
|
|
||||||
):
|
|
||||||
# the remaining pp is in between 0-2 slots
|
|
||||||
# so dump the whole position in this last exit
|
|
||||||
# therefore conducting so called "back loading"
|
|
||||||
# but **without** going past a net-zero pp.
|
|
||||||
order_size = abs_live_size
|
|
||||||
|
|
||||||
else:
|
# NOTE: front/back "loading" heurstic:
|
||||||
order_size = slot_size
|
# if the remaining pp is in between 0-1.5x a slot's
|
||||||
|
# worth, dump the whole position in this last exit
|
||||||
|
# therefore conducting so called "back loading" but
|
||||||
|
# **without** going past a net-zero pp. if the pp is
|
||||||
|
# > 1.5x a slot size, then front load: exit a slot's and
|
||||||
|
# expect net-zero to be acquired on the final exit.
|
||||||
|
slot_size < pp_size < round((1.5*slot_size), ndigits=ld)
|
||||||
|
):
|
||||||
|
order_size = abs_live_size
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'size': abs(round(order_size, ndigits=ld)),
|
'size': abs(round(order_size, ndigits=ld)),
|
||||||
|
@ -385,6 +401,8 @@ class SettingsPane:
|
||||||
# TODO: what should we do for fractional slot pps?
|
# TODO: what should we do for fractional slot pps?
|
||||||
self.fill_bar.set_slots(
|
self.fill_bar.set_slots(
|
||||||
slots,
|
slots,
|
||||||
|
|
||||||
|
# TODO: how to show "partial" slots?
|
||||||
# min(round(prop * slots), slots)
|
# min(round(prop * slots), slots)
|
||||||
min(ceil(prop * slots), slots)
|
min(ceil(prop * slots), slots)
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue