You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
TimeSequence iterator: this lets us encompass different ways of tracking "time" that are useful for trading strategies on a blockchain. This could be timestamps, block times, block numbers, or any sequence of increasing items.
TimestampPeriod: should be one of the concrete instantiations, has a start, end, optionally a freq that lets us use unix timestamps.
SimAsset: at the minimum should have an id, but the base class might not need anything else. Child classes would include:
CurrencyPair
PoolPair
etc
SimAssetSeries: Pandas Series-like abstraction for a SimAsset's market data. Common indexing and slicing operations should be supported but it is important to minimize allowed operations to reduce complex interactions in the codebase. Note associated price data likely reflects venue-specific liquidity considerations or may be from maker or taker perspective. This means there should probably be "tags" indicating these classifications.
TODOs:
TimeSequence interface design
implementation for timestamp periods
SimAsset interface design
PoolPair implementation
SimAssetSeries interface design (low priority, as we can eventually sub this in)
Market Data Sourcing
DataSource: has one or more query methods that let us pull data from files, external APIs, or any combination.
Produces series from main components: SimAsset and TimeSequence
Signature for a query could be: def query(self, sim_asset: SimAsset, time_sequence: TimeSequence) -> SimAssetSeries
data sources could be composable or load from multiple sources
TODOs:
DataSource interface design
FileDataSource
ApiDataSource
Market Data Querying
ReferenceMarket: this is the fictionalized external venue used as a reference for trading strategies.
an infinite-depth external venue, i.e. we can trade at any size
at the given price without market impact.
the "orderbook" is symmetric, i.e. trade direction doesn't matter.
one concrete implementation we need for current pipelines will just be a wrapper around SimAssetSeries, but the general idea is to separate data sourcing from trading strategy queries. For example, we can have a reference market that may take in parameters to generate prices via Monte-Carlo or more theoretically-driven means. It is the reference market that gets injected into the Simulation container.
Pools/Venues
SimMarket: target venue for the trading strategy; SimPool interface has everything we need for now. This abstraction lets us consider arbitrage routes through multiple pools or even across DEXes and/or CEXes.
SimMarketFactory
IoC Container
Using a dependency injection configuration utility like Google's gin, we can imitate an "Inversion of Control" container a la Spring. This lets users simply modify configuration files to "rewire" the container and run a custom simulation.
Proposed IoC-like container for a simulation looks like this:
@gin.configurable
class SimulationContext:
"""
Basically an 'IoC' container for the simulation application.
While Gin doesn't require such a container object, this makes configuration
more explicit.
"""
# all constructor args will be Gin injected
def __init__(
self,
time_sequence,
reference_market,
sim_market_factory,
sim_market_parameters,
trader_class,
log_class,
metric_classes,
):
self.time_sequence = time_sequence
self.reference_market = reference_market
self.sim_market_factory = sim_market_factory
self.sim_market_parameters = sim_market_parameters
self.trader_class = trader_class
self.log_class = log_class
self.metric_classes = metric_classes
def executor(
self,
sim_market,
):
"""
Executes a trading strategy for the given sim market
and time sequence.
"""
# These all use Gin injection, completely separating
# any need to consider constructor dependencies from
# this logic.
trader = self.trader_class()
log = self.log_class()
sim_market.prepare_for_run()
for timestep in self.time_sequence:
sim_market.prepare_for_trades(timestep)
sample = self.reference_market.prices(timestep)
trade_data = trader.process_time_sample(sample, sim_market)
log.update(price_sample=sample, trade_data=trade_data)
return log.compute_metrics()
@property
def configured_sim_markets(
self,
):
sim_market_parameters = self.sim_market_parameters
sim_market_factory = self.sim_market_factory
initial_params = sim_market_parameters.initial_parameters
all_run_params = sim_market_parameters.run_parameters
yield sim_market_factory.create(**initial_params)
for run_params in all_run_params:
init_kwargs = initial_params.copy()
init_kwargs.update(run_params)
sim_market = sim_market_factory.create(**init_kwargs)
yield sim_market
def run_simulation(
self,
ncpu=None,
):
configured_sim_markets = self.configured_sim_markets
initial_sim_market = next(configured_sim_markets)
output = run_pipeline(configured_sim_markets, self.executor, ncpu)
metrics = [Metric(pool=initial_sim_market) for Metric in self.metric_classes]
results = make_results(*output, metrics)
return results
Basic building blocks
Core
TimeSequence
iterator: this lets us encompass different ways of tracking "time" that are useful for trading strategies on a blockchain. This could be timestamps, block times, block numbers, or any sequence of increasing items.TimestampPeriod
: should be one of the concrete instantiations, has astart
,end
, optionally afreq
that lets us use unix timestamps.SimAsset
: at the minimum should have anid
, but the base class might not need anything else. Child classes would include:CurrencyPair
PoolPair
SimAssetSeries
: Pandas Series-like abstraction for aSimAsset
's market data. Common indexing and slicing operations should be supported but it is important to minimize allowed operations to reduce complex interactions in the codebase. Note associated price data likely reflects venue-specific liquidity considerations or may be from maker or taker perspective. This means there should probably be "tags" indicating these classifications.TODOs:
TimeSequence
interface designSimAsset
interface designPoolPair
implementationSimAssetSeries
interface design (low priority, as we can eventually sub this in)Market Data Sourcing
DataSource
: has one or more query methods that let us pull data from files, external APIs, or any combination.SimAsset
andTimeSequence
def query(self, sim_asset: SimAsset, time_sequence: TimeSequence) -> SimAssetSeries
TODOs:
DataSource
interface designFileDataSource
ApiDataSource
Market Data Querying
ReferenceMarket
: this is the fictionalized external venue used as a reference for trading strategies.def prices(self, sim_assets: List[SimAsset], timestep) -> List[float]
at the given price without market impact.
one concrete implementation we need for current pipelines will just be a wrapper around
SimAssetSeries
, but the general idea is to separate data sourcing from trading strategy queries. For example, we can have a reference market that may take in parameters to generate prices via Monte-Carlo or more theoretically-driven means. It is the reference market that gets injected into the Simulation container.Pools/Venues
SimMarket
: target venue for the trading strategy;SimPool
interface has everything we need for now. This abstraction lets us consider arbitrage routes through multiple pools or even across DEXes and/or CEXes.SimMarketFactory
IoC Container
Using a dependency injection configuration utility like Google's
gin
, we can imitate an "Inversion of Control" container a la Spring. This lets users simply modify configuration files to "rewire" the container and run a custom simulation.Proposed IoC-like container for a simulation looks like this:
It can then be run with:
The text was updated successfully, but these errors were encountered: