Skip to content

Commit

Permalink
feat: capped futures (#682)
Browse files Browse the repository at this point in the history
* feat: implement capped futures

* feat: restructure configs for capped futures

* fix: correct oracle decimal places

* fix: ensure finalise transactions

* chore: run make black
  • Loading branch information
cdummett authored Jul 12, 2024
1 parent 7ebdecd commit f09c26c
Show file tree
Hide file tree
Showing 17 changed files with 335 additions and 58 deletions.
39 changes: 38 additions & 1 deletion vega_sim/api/market.py
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,7 @@ class FutureProduct(Config):
"settlement_data_property": "future.settlement",
"trading_termination_property": "future.termination",
},
"cap": None,
}
}

Expand All @@ -806,6 +807,7 @@ def load(self, opt: Optional[Union[dict, str]] = None):
if config["data_source_spec_binding"] is not None
else None
)
self.cap = FutureCap(config["cap"]) if config["cap"] is not None else None

def build(self, oracle_pubkey: str):
if None in [
Expand All @@ -825,9 +827,42 @@ def build(self, oracle_pubkey: str):
oracle_pubkey=oracle_pubkey
),
data_source_spec_binding=self.data_source_spec_binding.build(),
cap=self.cap.build() if self.cap is not None else None,
)
return proto

def is_capped(self):
return self.cap is not None

def is_binary(self):
if not self.is_capped():
return False
return self.cap.binary_settlement == True


class FutureCap(Config):
OPTS = {
"default": {
"max_price": 1,
"binary_settlement": False,
"fully_collateralised": False,
}
}

def load(self, opt: Optional[Union[dict, str]] = None):
config = super().load(opt=opt)

self.max_price = config["max_price"]
self.binary_settlement = config["binary_settlement"]
self.fully_collateralised = config["fully_collateralised"]

def build(self):
return build.markets.future_cap(
max_price=self.max_price,
binary_settlement=self.binary_settlement,
fully_collateralised=self.fully_collateralised,
)


class PerpetualProduct(Config):
OPTS = {
Expand Down Expand Up @@ -1069,7 +1104,9 @@ def build(self, oracle_pubkey: str):
key=build.data.spec.property_key(
name=filter["key"]["name"],
type=filter["key"]["type"],
number_decimal_places=filter.get("number_decimal_places", None),
number_decimal_places=filter["key"].get(
"number_decimal_places", None
),
),
conditions=[
build.data.spec.condition(
Expand Down
2 changes: 2 additions & 0 deletions vega_sim/builders/governance.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,13 +202,15 @@ def future_product(
data_source_spec_for_settlement_data: vega_protos.data_source.DataSourceDefinition,
data_source_spec_for_trading_termination: vega_protos.data_source.DataSourceDefinition,
data_source_spec_binding: vega_protos.markets.DataSourceSpecToFutureBinding,
cap: Optional[vega_protos.markets.FutureCap] = None,
) -> vega_protos.governance.FutureProduct:
return vega_protos.governance.FutureProduct(
settlement_asset=settlement_asset,
quote_name=quote_name,
data_source_spec_for_settlement_data=data_source_spec_for_settlement_data,
data_source_spec_for_trading_termination=data_source_spec_for_trading_termination,
data_source_spec_binding=data_source_spec_binding,
cap=cap,
)


Expand Down
15 changes: 15 additions & 0 deletions vega_sim/builders/markets.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ def future_product(
data_source_spec_for_settlement_data: vega_protos.data_source.DataSourceDefinition,
data_source_spec_for_trading_termination: vega_protos.data_source.DataSourceDefinition,
data_source_spec_binding: vega_protos.markets.DataSourceSpecToFutureBinding,
cap: Optional[vega_protos.markets.FutureCap] = None,
) -> vega_protos.markets.Future:
return vega_protos.markets.Future(
settlement_asset=settlement_asset,
quote_name=quote_name,
data_source_spec_for_settlement_data=data_source_spec_for_settlement_data,
data_source_spec_for_trading_termination=data_source_spec_for_trading_termination,
data_source_spec_binding=data_source_spec_binding,
cap=cap,
)


Expand All @@ -47,6 +49,19 @@ def data_source_spec_to_future_binding(
)


@raise_custom_build_errors
def future_cap(
max_price: float,
binary_settlement: bool,
fully_collateralised: bool,
) -> vega_protos.markets.FutureCap:
return vega_protos.markets.FutureCap(
max_price=str(max_price),
binary_settlement=binary_settlement,
fully_collateralised=fully_collateralised,
)


# TODO: Implement build methods for spot markets
@raise_custom_build_errors
def spot() -> vega_protos.markets.Spot:
Expand Down
41 changes: 27 additions & 14 deletions vega_sim/configs/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from typing import Optional, Union, Dict, Iterable

from vega_sim.api.market import MarketConfig, SpotMarketConfig
from vega_sim.api.helpers import num_from_padded_int
from vega_sim.environment.agent import StateAgentWithWallet
from vega_sim.network_service import VegaServiceNetwork
from vega_sim.null_service import VegaServiceNull
Expand Down Expand Up @@ -134,24 +135,36 @@ def step(self, vega_state):
)

def finalise(self):
if self.is_future:
if self.is_spot:
return
# Submit termination data
self.vega.submit_oracle_data(
key_name=self.key_name,
wallet_name=self.wallet_name,
name=self.termination_oracle,
type=protos.vega.data.v1.spec.PropertyKey.Type.TYPE_BOOLEAN,
value=True,
)
for name, number_decimal_places in self.data_oracles.items():
settlement_price = self.price
if self.is_future and self.market_config.instrument.future.is_capped():
max_price = num_from_padded_int(
self.market_config.instrument.future.cap.max_price,
self.market_config.decimal_places,
)
settlement_price = min(settlement_price, max_price)
if self.market_config.instrument.future.is_binary():
normalised_price = settlement_price / max_price
rounded_price = round(normalised_price * 2) / 2
settlement_price = rounded_price * max_price
self.vega.submit_oracle_data(
key_name=self.key_name,
wallet_name=self.wallet_name,
name=self.termination_oracle,
type=protos.vega.data.v1.spec.PropertyKey.Type.TYPE_BOOLEAN,
value=True,
name=name,
type=protos.vega.data.v1.spec.PropertyKey.Type.TYPE_INTEGER,
value=settlement_price,
decimals=number_decimal_places,
)
if self.is_future or self.is_perpetual:
for name, number_decimal_places in self.data_oracles.items():
self.vega.submit_oracle_data(
key_name=self.key_name,
wallet_name=self.wallet_name,
name=name,
type=protos.vega.data.v1.spec.PropertyKey.Type.TYPE_INTEGER,
value=self.price,
decimals=number_decimal_places,
)

def __find_or_create_asset(self, symbol: str):
# Check if asset exists and create it if not
Expand Down
4 changes: 2 additions & 2 deletions vega_sim/configs/research/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from . import spot, future, perpetual, ESHRUSDT, HLPUSDT, SPOT
from . import fcap, spot, futr, perp, ESHRUSDT, HLPUSDT, SPOT

__all__ = ["spot", "future", "perpetual", "ESHRUSDT", "HLPUSDT", "SPOT"]
__all__ = ["fcap", "spot", "futr", "perp", "ESHRUSDT", "HLPUSDT", "SPOT"]
108 changes: 108 additions & 0 deletions vega_sim/configs/research/fcap/ENGFRA_POS.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
"""ENGFRA_POS.py
Market config for a capped future market. Market setup as a market for
taking bets on the final possession for a team in a football game.
"""

from vega_sim.api.market import MarketConfig

CONFIG = MarketConfig(
{
"decimalPlaces": "4",
"positionDecimalPlaces": "1",
"tickSize": "1",
"instrument": {
"code": "ENGvFRA-POS/USDT-FCAP",
"name": "Euro 2024 England vs. France (Final Possession) / Tether USD (Capped Future)",
"future": {
"settlementAsset": "bf1e88d19db4b3ca0d1d5bdb73718a01686b18cf731ca26adedf3c8b83802bba",
"quoteName": "USDT",
"dataSourceSpecForSettlementData": {
"external": {
"oracle": {
"signers": [{"pubKey": {"key": None}}],
"filters": [
{
"key": {
"name": "prices.engfra.value",
"type": "TYPE_INTEGER",
"numberDecimalPlaces": "18",
},
"conditions": [
{
"operator": "OPERATOR_GREATER_THAN",
"value": "0",
},
],
}
],
}
}
},
"dataSourceSpecForTradingTermination": {
"external": {
"oracle": {
"signers": [{"pubKey": {"key": None}}],
"filters": [
{
"key": {
"name": "termination",
"type": "TYPE_BOOLEAN",
},
"conditions": [
{"operator": "OPERATOR_EQUALS", "value": "true"}
],
}
],
}
}
},
"dataSourceSpecBinding": {
"settlementDataProperty": "prices.engfra.value",
"tradingTerminationProperty": "termination",
},
# "cap": {
# "maxPrice": 1000000,
# "binarySettlement": False,
# "fullyCollateralised": True,
# },
},
},
"metadata": [
"quote:USDT",
"class:fcap",
"future",
"sector:defi",
],
"priceMonitoringParameters": {"triggers": []},
"liquidityMonitoringParameters": {
"targetStakeParameters": {"timeWindow": "3600", "scalingFactor": 0.05},
"triggeringRatio": "",
"auctionExtension": "0",
},
"logNormal": {
"riskAversionParameter": 0.000001,
"tau": 0.000003995,
"params": {"mu": 0, "r": 0, "sigma": 1},
},
"linearSlippageFactor": "0.001",
"quadraticSlippageFactor": "",
"liquiditySlaParameters": {
"priceRange": "0.03",
"commitmentMinTimeFraction": "0.75",
"performanceHysteresisEpochs": "1",
"slaCompetitionFactor": "0.8",
},
"liquidityFeeSettings": {"method": "METHOD_MARGINAL_COST"},
"liquidationStrategy": {
"disposalTimeStep": "1",
"disposalFraction": "1",
"fullDisposalSize": "1000000",
"maxFractionConsumed": "0.1",
"disposalSlippageRange": "0.03",
},
"markPriceConfiguration": {
"compositePriceType": "COMPOSITE_PRICE_TYPE_LAST_TRADE",
},
}
)
Loading

0 comments on commit f09c26c

Please sign in to comment.