diff --git a/vega_sim/scenario/benchmark/configs.py b/vega_sim/scenario/benchmark/configs.py index af7194e87..9c59f9ca9 100644 --- a/vega_sim/scenario/benchmark/configs.py +++ b/vega_sim/scenario/benchmark/configs.py @@ -1,4 +1,4 @@ -from typing import Union +from typing import Union, Optional from vega_sim.api.market import MarketConfig, SpotMarketConfig @@ -9,8 +9,10 @@ def __init__( initial_price: float, annualised_volatility: float, notional_trade_volume: int, + historic_data_code: Optional[str] = None, ): self.market_config = market_config self.initial_price = initial_price self.annualised_volatility = annualised_volatility self.notional_trade_volume = notional_trade_volume + self.historic_data_code = historic_data_code diff --git a/vega_sim/scenario/benchmark/registry.py b/vega_sim/scenario/benchmark/registry.py index d90911ee3..6da50f38b 100644 --- a/vega_sim/scenario/benchmark/registry.py +++ b/vega_sim/scenario/benchmark/registry.py @@ -1,3 +1,5 @@ +import datetime + import vega_sim.configs as configs from vega_sim.scenario.benchmark.configs import BenchmarkConfig from vega_sim.scenario.benchmark.scenario import BenchmarkScenario @@ -62,6 +64,7 @@ initial_price=70000, annualised_volatility=2, notional_trade_volume=100, + historic_data_code="BTC-USD", ) ], ), @@ -86,6 +89,7 @@ initial_price=4000, annualised_volatility=2, notional_trade_volume=100, + historic_data_code="ETH-USD", ) ], ), diff --git a/vega_sim/scenario/benchmark/run.py b/vega_sim/scenario/benchmark/run.py index e7ccc7fe7..707fe6b0b 100644 --- a/vega_sim/scenario/benchmark/run.py +++ b/vega_sim/scenario/benchmark/run.py @@ -4,6 +4,7 @@ import datetime import argparse +from typing import Optional from vega_sim.null_service import VegaServiceNull, Ports from vega_sim.scenario.constants import Network @@ -25,6 +26,7 @@ def _run( output_dir: str = "plots", core_metrics_port: int = 2723, data_node_metrics_port: int = 3651, + genesis_time: Optional[datetime.datetime] = None, ): with VegaServiceNull( @@ -38,6 +40,7 @@ def _run( Ports.METRICS: core_metrics_port, Ports.DATA_NODE_METRICS: data_node_metrics_port, }, + genesis_time=genesis_time, ) as vega: scenario.run_iteration( vega=vega, @@ -146,11 +149,17 @@ def _run( parser = argparse.ArgumentParser() parser.add_argument("-m", "--market", required=True, type=str) parser.add_argument("-s", "--steps", default=600, type=int) + parser.add_argument("-i", "--interval", default=1, type=int) parser.add_argument("-p", "--pause", action="store_true") parser.add_argument("-d", "--debug", action="store_true") parser.add_argument("-o", "--output", action="store_true") parser.add_argument("-c", "--console", action="store_true") parser.add_argument("-w", "--wallet", action="store_true") + parser.add_argument( + "--datetime", + type=datetime.datetime.fromisoformat, + help="Specify datetime to retrieve data from (format: YYYY-MM-DD:HH:mm:ss).", + ) parser.add_argument("--core-metrics-port", default=2723, type=int) parser.add_argument("--data-node-metrics-port", default=3651, type=int) args = parser.parse_args() @@ -162,7 +171,10 @@ def _run( if args.market not in REGISTRY: raise ValueError(f"Market {args.market} not found") - scenario = REGISTRY[args.market].num_steps = args.steps + scenario: BenchmarkScenario = REGISTRY[args.market] + scenario.num_steps = args.steps + scenario.step_length_seconds = args.interval + scenario.historic_start_datetime = args.datetime _run( scenario=REGISTRY[args.market], @@ -172,4 +184,5 @@ def _run( output=args.output, core_metrics_port=args.core_metrics_port, data_node_metrics_port=args.data_node_metrics_port, + genesis_time=args.datetime, ) diff --git a/vega_sim/scenario/benchmark/scenario.py b/vega_sim/scenario/benchmark/scenario.py index 3966884ce..adb0a8467 100644 --- a/vega_sim/scenario/benchmark/scenario.py +++ b/vega_sim/scenario/benchmark/scenario.py @@ -1,10 +1,15 @@ +import datetime import numpy as np from typing import Optional, Dict, Any, List from vega_sim.api.market import MarketConfig from vega_sim.scenario.scenario import Scenario from vega_sim.scenario.benchmark.configs import BenchmarkConfig -from vega_sim.scenario.common.utils.price_process import random_walk +from vega_sim.scenario.common.utils.price_process import ( + random_walk, + get_historic_price_series, + Granularity, +) from vega_sim.scenario.constants import Network from vega_sim.null_service import VegaServiceNull from vega_sim.environment.environment import ( @@ -26,13 +31,41 @@ ) +def _historic_price_process( + product_id: str, + num_steps: int, + step_length_seconds: float, + start: datetime.datetime, +) -> List[float]: + if step_length_seconds > 86400: + granularity = Granularity.DAY + elif step_length_seconds > 21600: + granularity = Granularity.SIX_HOUR + elif step_length_seconds > 6480: + granularity = Granularity.HOUR + elif step_length_seconds > 900: + granularity = Granularity.FIFTEEN_MINUTE + elif step_length_seconds > 300: + granularity = Granularity.FIVE_MINUTE + else: + granularity = Granularity.MINUTE + end = start + datetime.timedelta(seconds=1.1 * num_steps * granularity.value) + return get_historic_price_series( + product_id=product_id, + granularity=granularity, + interpolation=f"{step_length_seconds}S", + start=str(start), + end=str(end), + ).values + + def _create_price_process( random_state: np.random.RandomState, num_steps, decimal_places, initial_price, price_sigma, -): +) -> List[float]: price_process = [initial_price] while len(price_process) < num_steps + 1: @@ -75,6 +108,7 @@ def __init__( block_length_seconds: float = 1, step_length_seconds: Optional[float] = None, initial_network_parameters: Dict[str, Any] = None, + historic_start_datetime: Optional[str] = None, output: bool = True, ): super().__init__() @@ -87,6 +121,7 @@ def __init__( ) self.block_length_seconds = block_length_seconds self.transactions_per_block = transactions_per_block + self.historic_start_datetime = historic_start_datetime self.output = output self.benchmark_configs = benchmark_configs @@ -123,16 +158,26 @@ def configure_agents( else benchmark_config.market_config.decimal_places ) - # Create fuzzed price process - price_process = _create_price_process( - random_state=self.random_state, - num_steps=self.num_steps, - decimal_places=market_decimal_places, - initial_price=benchmark_config.initial_price, - price_sigma=benchmark_config.annualised_volatility - * np.sqrt(self.step_length_seconds / (365.25 * 24 * 60 * 60)) - * benchmark_config.initial_price, - ) + if ( + self.historic_start_datetime is not None + and benchmark_config.historic_data_code is not None + ): + price_process = _historic_price_process( + product_id=benchmark_config.historic_data_code, + num_steps=self.num_steps, + step_length_seconds=self.step_length_seconds, + start=self.historic_start_datetime, + ) + else: + price_process = _create_price_process( + random_state=self.random_state, + num_steps=self.num_steps, + decimal_places=market_decimal_places, + initial_price=benchmark_config.initial_price, + price_sigma=benchmark_config.annualised_volatility + * np.sqrt(self.step_length_seconds / (365.25 * 24 * 60 * 60)) + * benchmark_config.initial_price, + ) self.agents.append( ConfigurableMarketManager(