Add non-state-incremented calculation methods
Since we're going to need them anyway for desired features, add 2 new `Position` methods: - `.calc_be_price()` which computes the breakeven cost basis price from the entries in the clears table. - `.calc_size()` which just sums the clear sizes. Add a `cost_scalar: float` control to the `.update_from_trans()` method to allow manual adjustment of the cost weighting for the case where a "non-symmetrical" model is wanted. Go back to always trying to write the backing ledger files on exit, even when there's an error (obvs without the `return` in the `finally:` block f$#% up).historical_breakeven_pp_price
parent
a3d46f713e
commit
45bef0cea9
70
piker/pp.py
70
piker/pp.py
|
@ -83,8 +83,9 @@ def open_trade_ledger(
|
|||
print(f'Ledger load took {time.time() - start}s')
|
||||
cpy = ledger.copy()
|
||||
|
||||
try:
|
||||
yield cpy
|
||||
|
||||
finally:
|
||||
if cpy != ledger:
|
||||
# TODO: show diff output?
|
||||
# https://stackoverflow.com/questions/12956957/print-diff-of-python-dictionaries
|
||||
|
@ -276,6 +277,62 @@ class Position(Struct):
|
|||
|
||||
return new_size, self.be_price
|
||||
|
||||
def calc_be_price(self) -> float:
|
||||
|
||||
size: float = 0
|
||||
cb_tot_size: float = 0
|
||||
cost_basis: float = 0
|
||||
be_price: float = 0
|
||||
|
||||
for tid, entry in self.clears.items():
|
||||
clear_size = entry['size']
|
||||
clear_price = entry['price']
|
||||
new_size = size + clear_size
|
||||
|
||||
# old size minus the new size gives us size diff with
|
||||
# +ve -> increase in pp size
|
||||
# -ve -> decrease in pp size
|
||||
size_diff = abs(new_size) - abs(size)
|
||||
|
||||
if new_size == 0:
|
||||
cost_basis = 0
|
||||
cb_tot_size = 0
|
||||
be_price = 0
|
||||
|
||||
elif size_diff > 0:
|
||||
# only an increaze in size of the position contributes
|
||||
# the breakeven price, a decrease does not.
|
||||
|
||||
cost_basis += (
|
||||
# weighted price per unit of
|
||||
clear_price * abs(clear_size)
|
||||
+
|
||||
# transaction cost
|
||||
(copysign(1, new_size) * entry['cost'] * 2)
|
||||
)
|
||||
cb_tot_size += abs(clear_size)
|
||||
be_price = cost_basis / cb_tot_size
|
||||
|
||||
size = new_size
|
||||
|
||||
# print(
|
||||
# f'cb: {cost_basis}\n'
|
||||
# f'size: {size}\n'
|
||||
# f'clear_size: {clear_size}\n'
|
||||
# f'clear_price: {clear_price}\n\n'
|
||||
|
||||
# f'cb_tot_size: {cb_tot_size}\n'
|
||||
# f'be_price: {be_price}\n\n'
|
||||
# )
|
||||
|
||||
return be_price
|
||||
|
||||
def calc_size(self) -> float:
|
||||
size: float = 0
|
||||
for tid, entry in self.clears.items():
|
||||
size += entry['size']
|
||||
return size
|
||||
|
||||
def minimize_clears(
|
||||
self,
|
||||
|
||||
|
@ -310,6 +367,8 @@ class PpTable(Struct):
|
|||
def update_from_trans(
|
||||
self,
|
||||
trans: dict[str, Transaction],
|
||||
cost_scalar: float = 2,
|
||||
|
||||
) -> dict[str, Position]:
|
||||
|
||||
pps = self.pps
|
||||
|
@ -354,7 +413,7 @@ class PpTable(Struct):
|
|||
# and presume the worst case of the same cost
|
||||
# to exit this transaction (even though in reality
|
||||
# it will be dynamic based on exit stratetgy).
|
||||
cost=2*r.cost,
|
||||
cost=cost_scalar*r.cost,
|
||||
)
|
||||
|
||||
# track clearing data
|
||||
|
@ -764,11 +823,10 @@ def open_pps(
|
|||
clears=clears,
|
||||
)
|
||||
|
||||
try:
|
||||
yield table
|
||||
|
||||
if not write_on_exit:
|
||||
return
|
||||
|
||||
finally:
|
||||
if write_on_exit:
|
||||
# TODO: show diff output?
|
||||
# https://stackoverflow.com/questions/12956957/print-diff-of-python-dictionaries
|
||||
print(f'Updating ``pps.toml`` for {path}:\n')
|
||||
|
|
Loading…
Reference in New Issue