Can now specify a different 'hedging' interval in the marketmaker.

This commit is contained in:
Geoff Taylor 2022-01-21 17:53:25 +00:00
parent 1967a63cc6
commit 0be350a134
2 changed files with 64 additions and 16 deletions

View File

@ -38,8 +38,10 @@ parser.add_argument("--existing-order-tolerance", type=Decimal, default=Decimal(
help="tolerance in price and quantity when matching existing orders or cancelling/replacing")
parser.add_argument("--redeem-threshold", type=Decimal,
help="threshold above which liquidity incentives will be automatically moved to the account (default: no moving)")
parser.add_argument("--pulse-interval", type=int, default=10,
parser.add_argument("--pulse-interval", type=float, default=10.0,
help="number of seconds between each 'pulse' of the market maker")
parser.add_argument("--hedging-pulse-interval", type=float,
help="number of seconds between each 'pulse' of the hedger (if hedging configured) - defaults to the --pulse-interval value if not specified")
parser.add_argument("--hedging-market", type=str, help="spot market symbol to use for hedging (e.g. ETH/USDC)")
parser.add_argument("--hedging-max-price-slippage-factor", type=Decimal, default=Decimal("0.05"),
help="the maximum value the IOC hedging order price can slip by when hedging (default is 0.05 for 5%%)")
@ -164,7 +166,7 @@ mango.InstrumentValue.report([asset for asset in account.net_values if asset is
manager.open()
def pulse_action(_: int) -> None:
def combined_pulse_action(_: int) -> None:
try:
context.client.require_data_from_fresh_slot()
model_state: mango.ModelState = model_state_builder.build(context)
@ -174,14 +176,50 @@ def pulse_action(_: int) -> None:
logging.error(f"Pulse action failed: {traceback.format_exc()}")
pulse_disposable = rx.interval(args.pulse_interval).pipe(
def marketmaking_pulse_action(_: int) -> None:
try:
context.client.require_data_from_fresh_slot()
model_state: mango.ModelState = model_state_builder.build(context)
market_maker.pulse(context, model_state)
except Exception:
logging.error(f"Pulse action failed: {traceback.format_exc()}")
def hedging_pulse_action(_: int) -> None:
try:
model_state: mango.ModelState = model_state_builder.build(context)
hedger.pulse(context, model_state)
except Exception:
logging.error(f"Pulse action failed: {traceback.format_exc()}")
hedging_pulse_interval: float = args.hedging_pulse_interval or args.pulse_interval
separate_hedge_pulse = False
if isinstance(hedger, mango.hedging.NullHedger):
logging.info(f"Using a pulse action with an interval of {args.pulse_interval} seconds.")
pulse_action = marketmaking_pulse_action
elif hedging_pulse_interval == args.pulse_interval:
logging.info(f"Using a combined pulse action with an interval of {args.pulse_interval} seconds.")
pulse_action = combined_pulse_action
else:
logging.info(
f"Using separate pulse actions with a marketmaking interval of {args.pulse_interval} seconds and a hedging interval of {hedging_pulse_interval} seconds.")
pulse_action = marketmaking_pulse_action
hedging_pulse_disposable = rx.interval(hedging_pulse_interval).pipe(
rx.operators.observe_on(context.create_thread_pool_scheduler()),
rx.operators.start_with(-1),
rx.operators.catch(mango.observable_pipeline_error_reporter),
rx.operators.retry()
).subscribe(mango.create_backpressure_skipping_observer(on_next=hedging_pulse_action, on_error=mango.log_subscription_error))
disposer.add_disposable(hedging_pulse_disposable)
marketmaking_pulse_disposable = rx.interval(args.pulse_interval).pipe(
rx.operators.observe_on(context.create_thread_pool_scheduler()),
rx.operators.start_with(-1),
rx.operators.catch(mango.observable_pipeline_error_reporter),
rx.operators.retry()
).subscribe(
on_next=pulse_action)
disposer.add_disposable(pulse_disposable)
).subscribe(mango.create_backpressure_skipping_observer(on_next=pulse_action, on_error=mango.log_subscription_error))
disposer.add_disposable(marketmaking_pulse_disposable)
# Wait - don't exit. Exiting will be handled by signals/interrupts.
waiter = threading.Event()

View File

@ -56,21 +56,31 @@ class PerpToSpotHedger(Hedger):
def pulse(self, context: mango.Context, model_state: mango.ModelState) -> None:
try:
# Latency can be important here so fetch fresh Account data in one gulp.
fresh_data: typing.Sequence[mango.AccountInfo] = mango.AccountInfo.load_multiple(
context, [model_state.group.address, model_state.group.cache, model_state.account.address])
fresh_group: mango.Group = mango.Group.parse_with_context(context, fresh_data[0])
fresh_cache: mango.Cache = mango.Cache.parse(fresh_data[1])
fresh_account: mango.Account = mango.Account.parse(fresh_data[2], fresh_group, fresh_cache)
perp_account: typing.Optional[mango.PerpAccount] = fresh_account.perp_accounts_by_index[self.market_index]
perp_account: typing.Optional[mango.PerpAccount] = model_state.account.perp_accounts_by_index[self.market_index]
if perp_account is None:
raise Exception(
f"Could not find perp account at index {self.market_index} in account {fresh_account.address}.")
f"Could not find perp account at index {self.market_index} in account {model_state.account.address}.")
basket_token: typing.Optional[mango.AccountSlot] = fresh_account.slots_by_index[self.market_index]
basket_token: typing.Optional[mango.AccountSlot] = model_state.account.slots_by_index[self.market_index]
if basket_token is None:
raise Exception(
f"Could not find basket token at index {self.market_index} in account {fresh_account.address}.")
f"Could not find basket token at index {self.market_index} in account {model_state.account.address}.")
# # Latency can be important here so fetch fresh Account data in one gulp.
# fresh_data: typing.Sequence[mango.AccountInfo] = mango.AccountInfo.load_multiple(
# context, [model_state.group.address, model_state.group.cache, model_state.account.address])
# fresh_group: mango.Group = mango.Group.parse_with_context(context, fresh_data[0])
# fresh_cache: mango.Cache = mango.Cache.parse(fresh_data[1])
# fresh_account: mango.Account = mango.Account.parse(fresh_data[2], fresh_group, fresh_cache)
# perp_account: typing.Optional[mango.PerpAccount] = fresh_account.perp_accounts_by_index[self.market_index]
# if perp_account is None:
# raise Exception(
# f"Could not find perp account at index {self.market_index} in account {fresh_account.address}.")
# basket_token: typing.Optional[mango.AccountSlot] = fresh_account.slots_by_index[self.market_index]
# if basket_token is None:
# raise Exception(
# f"Could not find basket token at index {self.market_index} in account {fresh_account.address}.")
token_balance: mango.InstrumentValue = basket_token.net_value
perp_position: mango.InstrumentValue = perp_account.base_token_value