Dollar Cost Averaging
Background
Dollar cost averaging (DCA) is an investment strategy that involves regularly investing a fixed amount of money into a particular asset regardless of the asset's price. This means purchasing more shares when prices are low and fewer shares when prices are high. The main objective is to reduce the impact of volatility on the overall purchase and avoid the pitfalls of trying to time the market.
![Dollar Cost Averaging Strategy](/docs/dollar-cost-averaging.png)
Dollar Cost Averaging Strategy
Regardless of the price of token y, we swap self.buying_amount
number of token x for token y. We do this trade every self.min_dist
block
if we have enough token x (more than 0) in the agent's portfolio.
![Dollar Cost Averaging Strategy Rewards](/docs/dca-sim1.png)
How To Run
Installation
Follow our Getting Started guide to install the dojo library and other required tools.
Then clone the dojo_examples
repository and go into the relevant directory.
git clone https://github.com/CompassLabs/dojo_examples.git
cd dojo_examples/examples/dollar_cost_averaging
Running
Download the dashboard to view the simulation results.
To view example simulation data, download results.db
and click 'Add A Simulation' on the dashboard.
To run the simulation yourself, use the following command.
python run.py
This command will setup your local blockchain, contracts, accounts and agents. You can then access your results on your Dojo dashboard by connecting to a running simulation.
Step-By-Step Explanation
Initialization
We create a subclass of BasePolicy
called DCAPolicy
which takes in 2 parameters: buying_amount
and min_dist
.
buying_amount
specifies the amount of tokens we should trade for the other tokenmin_dist
specifies the time interval in blocks between each trade.
On the Ethereum blockchain, the block time is approximately 12 seconds, while the block time on Arbitrum is ~0.26 seconds.
class DCAPolicy(BasePolicy):
"""Dollar Cost Averaging policy for a UniswapV3Env with a single pool.
:param agent: The agent which is using this policy.
:param buying_amount: The number of tokens to swap at each trade.
:param min_dist: The interval to swap tokens. The agent will only swap tokens if the
last trade was at least min_dist blocks ago.
"""
def __init__(self, agent: BaseAgent, buying_amount: float, min_dist: int) -> None:
super().__init__(agent=agent)
self.buying_amount = buying_amount
self.min_dist = min_dist
self.last_trade_block = 0
Signal Calculation
![Dollar Cost Averaging Strategy Wealth Difference](/docs/dca-sim2.png)
Signals allow us to easily view data on our Dojo dashboard. In this example, we are adding a signal to monitor the difference in wealth if the agent bought the token all at once at current price vs. dollar cost averaging.
pool = obs.pools[0]
token0, token1 = obs.pool_tokens(pool)
portfolio = self.agent.portfolio()
# add a signal to obs to monitor the difference in wealth if the agent bought the token all at once vs. dollar cost averaging
token0_balance = portfolio.get(token0, 0)
token1_balance = portfolio.get(token1, 0)
# calculate the current value of the portfolio if the agent bought the token all at once
value_if_held = self.agent.initial_portfolio[
token0
] + self.agent.initial_portfolio[token1] * obs.price(
token1, unit=token0, pool=pool
)
# calculate the current value of the portfolio if the agent used dollar cost averaging
dca_value = token0_balance * Decimal(1.0) + token1_balance * obs.price(
token1, unit=token0, pool=pool
)
wealth_difference = dca_value - value_if_held
obs.add_signal("Wealth Difference", wealth_difference)
Trade Execution
if (
portfolio[token0] >= self.buying_amount
and obs.block - self.last_trade_block >= self.min_dist
):
self.last_trade_block = obs.block
return [
UniswapV3Trade(
agent=self.agent,
pool=pool,
quantities=(Decimal(self.buying_amount), Decimal(0)),
)
]
return []
Here, we check if we have sufficient funds to purchase tokens and if enough time
has passed since our last trade. If both conditions are met, we set the last_trade_block
to the current block and return a UniswapV3Trade
object specifying the buying amount.
Otherwise, we return an empty list which means do nothing.
In the run.py
file, we create a pool, a Uniswap environment and an agent that implements the dollar cost averaging policy.
Results
You can download the results to this example below.
We offer a dashboard desktop application for visualizing your simulation results. This downloaded file can be added to the dashboard application.