From cde315af7273d4de33488933578064fa727bcd81 Mon Sep 17 00:00:00 2001 From: Jiajia-Cui <92106936+Jiajia-Cui@users.noreply.github.com> Date: Thu, 5 Sep 2024 16:52:44 +0100 Subject: [PATCH] feat: make drift term available (#701) * feat: make drift term available * feat: address comments * feat: add more asset to risky_trader * feat: tweaks for consistent AMM runs * feat: add cumulated trade volume plot * feat: reverse trade order * chore: tidy up * feat: address comments from Charlie * chore: run linter --------- Co-authored-by: Charlie --- vega_query/service/utils/party.py | 10 ++++-- vega_query/visualisations/overlay.py | 35 +++++++++++++++++++ vega_query/visualisations/plots/amm.py | 35 ++++++++++--------- vega_sim/scenario/amm/registry.py | 6 ++-- vega_sim/scenario/amm/scenario.py | 8 ++--- vega_sim/scenario/benchmark/configs.py | 2 ++ vega_sim/scenario/benchmark/scenario.py | 2 +- .../scenario/common/utils/price_process.py | 3 +- 8 files changed, 72 insertions(+), 29 deletions(-) diff --git a/vega_query/service/utils/party.py b/vega_query/service/utils/party.py index ae56324db..f1bb3d552 100644 --- a/vega_query/service/utils/party.py +++ b/vega_query/service/utils/party.py @@ -8,6 +8,8 @@ import pandas as pd +from vega_query.utils import timestamp_to_datetime + logger = getLogger(__name__) @@ -42,7 +44,9 @@ def historic_positions( data = defaultdict(lambda: defaultdict(int)) for trade in trades: position_after_trade = positions.get(trade.market_id, 0) - data[trade.timestamp][trade.market_id] = position_after_trade + data[timestamp_to_datetime(trade.timestamp)][ + trade.market_id + ] = position_after_trade match party_id: case trade.buyer: positions[trade.market_id] -= trade.size @@ -92,8 +96,8 @@ def historic_balances( ) if aggregated_balance.market_id is not "": account_key += f" | {aggregated_balance.market_id[:7]}" - data[aggregated_balance.timestamp][account_key] = int( - aggregated_balance.balance + data[timestamp_to_datetime(aggregated_balance.timestamp)][account_key] = ( + int(aggregated_balance.balance) ) df = pd.DataFrame.from_dict(data, orient="index").sort_index().ffill() diff --git a/vega_query/visualisations/overlay.py b/vega_query/visualisations/overlay.py index 42b216b3b..9b299454f 100644 --- a/vega_query/visualisations/overlay.py +++ b/vega_query/visualisations/overlay.py @@ -895,6 +895,41 @@ def overlay_volume( ax.step(x, y, label="volume", where="post") +def overlay_cumulative_volume( + ax: Axes, + trades: List[protos.vega.vega.Trade], + price_decimals: int, + size_decimals: int, + **kwargs, +): + x = [] # List to store timestamps + y = [] # List to store cumulative volume + cumulative_volume = 0 # Initialize cumulative volume + + for trade in reversed(trades): + # Convert timestamp to datetime for x-axis + timestamp = timestamp_to_datetime(trade.timestamp, nano=True) + x.append(timestamp) + + # Ensure price and size are available + if hasattr(trade, "price") and hasattr(trade, "size"): + price = padded_int_to_float(trade.price, price_decimals) + size = padded_int_to_float(trade.size, size_decimals) + + # Calculate traded volume (price * size) + volume = price * size if price != 0 else 0 + + # Accumulate volume (ensure volume is positive) + cumulative_volume += abs(volume) + y.append(cumulative_volume) + else: + # If price or size is missing, assume no change in cumulative volume + y.append(cumulative_volume) + + # Plot the cumulative volume data using step plot + ax.step(x, y, label="Cumulative Volume", where="post", **kwargs) + + def overlay_maker_fee( ax: Axes, trades: List[protos.vega.vega.Trade], diff --git a/vega_query/visualisations/plots/amm.py b/vega_query/visualisations/plots/amm.py index 05551b325..4fdddd5f4 100644 --- a/vega_query/visualisations/plots/amm.py +++ b/vega_query/visualisations/plots/amm.py @@ -65,13 +65,7 @@ def create( # Set unique colors for each party and request party specific information amms = service.api.data.list_amms(market_id=market.id) if party_ids is None: - # party_ids = __party_defaults_old(market_data_history=market_data_history) party_ids = __party_defaults(amms=amms) - # party_ids = __party_defaults(amms=amms) + __party_defaults_old( - # market_data_history=market_data_history - # ) - - print(party_ids) party_colors = __party_colors(party_ids) @@ -80,13 +74,13 @@ def create( ymin = ymax = 0 axes: List[Axes] = [] - axn0l = fig.add_subplot(gs[:, 0]) + axn0l = fig.add_subplot(gs[0, 0]) axn0r: Axes = axn0l.twinx() if market_data_history is not None: overlay_mark_price(axn0l, market_data_history, market.decimal_places) overlay_trading_mode(axn0r, market_data_history) - overlay_auction_starts(axn0r, market_data_history) - overlay_auction_ends(axn0r, market_data_history) + # overlay_auction_starts(axn0r, market_data_history) + # overlay_auction_ends(axn0r, market_data_history) axn0l.set_ylabel("USDT") axn0l.set_title( @@ -100,6 +94,10 @@ def create( axn0r.legend(loc="upper right", framealpha=1) axn0r.add_artist(leg) + ax10 = fig.add_subplot(gs[1, 0]) + ax10.set_title("Cumulated traded notional", loc="left") + ax10.set_ylabel("Market traded notional") + ax11 = fig.add_subplot(gs[0, 1]) ax11.set_title("AMM: Position", loc="left") ax11.set_ylabel("Open Volume") @@ -130,6 +128,13 @@ def create( date_range_start_timestamp=start_timestamp, date_range_end_timestamp=end_timestamp, ) + + overlay_cumulative_volume( + ax=ax10, + trades=trades, + price_decimals=market.decimal_places, + size_decimals=market.position_decimal_places, + ) overlay_position( ax=ax11, trades=trades, @@ -139,17 +144,13 @@ def create( ax11.get_lines()[-1].set_label(amm_party_id[:7]) # Reconstruct the AMMs aggregated balance from balance changes - aggregated_balances = service.api.data.list_balance_changes( - party_ids=[amm_party_id], + df = service.utils.party.historic_balances( + party_id=amm_party_id, + asset_id=asset.id, date_range_start_timestamp=start_timestamp, date_range_end_timestamp=end_timestamp, ) - overlay_aggregated_balances( - ax=ax21, - aggregated_balances=aggregated_balances, - asset_decimals=asset.details.decimals, - ) - ax21.get_lines()[-1].set_label(amm_party_id[:7]) + ax21.step(df.index, df.total, where="post", label="total") ax11.legend() ax21.legend() diff --git a/vega_sim/scenario/amm/registry.py b/vega_sim/scenario/amm/registry.py index a36fbddb1..14fb30436 100644 --- a/vega_sim/scenario/amm/registry.py +++ b/vega_sim/scenario/amm/registry.py @@ -13,13 +13,15 @@ initial_price=70000, annualised_volatility=0.5, notional_trade_volume=100, - process_theta=0.02, + process_theta=0.01, + process_drift=-10, ), ], - amm_liquidity_fee=0.001, + amm_liquidity_fee=0.0001, amm_update_frequency=0, initial_network_parameters={ "validators.epoch.length": "1h", + "market.fee.factors.makerFee": "0", }, ), } diff --git a/vega_sim/scenario/amm/scenario.py b/vega_sim/scenario/amm/scenario.py index 76eea7b51..317a38ff7 100644 --- a/vega_sim/scenario/amm/scenario.py +++ b/vega_sim/scenario/amm/scenario.py @@ -67,13 +67,13 @@ def configure_agents( wallet_name="AutomatedMarketMaker", key_name=f"AutomatedMarketMaker_{benchmark_config.market_config.instrument.code}_{str(i_agent).zfill(3)}", market_name=benchmark_config.market_config.instrument.name, - initial_asset_mint=2e6, - commitment_amount=1e5, + initial_asset_mint=1e6, + commitment_amount=7000, slippage_tolerance=0.05, proposed_fee=self.amm_liquidity_fee, price_process=iter(benchmark_config.price_process), - lower_bound_scaling=1 - 0.05, - upper_bound_scaling=1 + 0.05, + lower_bound_scaling=1 - 0.02, + upper_bound_scaling=1 + 0.02, leverage_at_lower_bound=20, leverage_at_upper_bound=20, update_bias=self.amm_update_frequency, diff --git a/vega_sim/scenario/benchmark/configs.py b/vega_sim/scenario/benchmark/configs.py index a50d88ae2..0b90e1f8d 100644 --- a/vega_sim/scenario/benchmark/configs.py +++ b/vega_sim/scenario/benchmark/configs.py @@ -11,10 +11,12 @@ def __init__( notional_trade_volume: int, risky_trader_funds: int = 1_000, process_theta: float = 0, + process_drift: float = 0, ): self.market_config = market_config self.initial_price = initial_price self.process_theta = process_theta + self.process_drift = process_drift self.annualised_volatility = annualised_volatility self.notional_trade_volume = notional_trade_volume self.risky_trader_funds = risky_trader_funds diff --git a/vega_sim/scenario/benchmark/scenario.py b/vega_sim/scenario/benchmark/scenario.py index c2def24bf..ffb33c6c3 100644 --- a/vega_sim/scenario/benchmark/scenario.py +++ b/vega_sim/scenario/benchmark/scenario.py @@ -88,10 +88,10 @@ def configure_agents( x0=benchmark_config.initial_price, mu=benchmark_config.initial_price, theta=benchmark_config.process_theta, + drift=benchmark_config.process_drift, sigma=benchmark_config.annualised_volatility * np.sqrt(self.step_length_seconds / (365.25 * 24 * 60 * 60)) * benchmark_config.initial_price, - drift=0, ) self.agents.append( ConfigurableMarketManager( diff --git a/vega_sim/scenario/common/utils/price_process.py b/vega_sim/scenario/common/utils/price_process.py index b6ae763cc..39e72b29b 100644 --- a/vega_sim/scenario/common/utils/price_process.py +++ b/vega_sim/scenario/common/utils/price_process.py @@ -336,9 +336,8 @@ def ou_price_process(n, theta=0.15, mu=0.0, sigma=0.2, x0=1.0, drift=0.0): x[0] = x0 for t in range(1, n): dx = ( - theta * (mu - x[t - 1]) * dt + theta * ((mu + t * drift) - x[t - 1]) * dt + sigma * np.sqrt(dt) * np.random.normal() - + drift * dt ) x[t] = x[t - 1] + dx return x