Moving Averages
Background
A moving averages trading strategy involves using moving averages (MA's) to identify market trends. A moving average smooths out price data by creating a constantly updated average price over a specific period. Common periods used are 10, 20, 50, or 200 days.
The two most common types are the Simple Moving Average (SMA), which calculates the average price over a given number of periods, and the Exponential Moving Average (EMA), which gives more weight to recent prices.
Moving averages help traders identify the overall direction of an asset's price movement and can act as support or resistance levels.
They are also used to generate trading signals. For example, a crossover of a short-term MA above a long-term MA (golden cross) signals a potential uptrend, while a crossover below (death cross) signals a potential downtrend.
![Moving Average Strategy](/docs/moving-average.png)
Moving Averages Strategy
Our trading strategy is based on the following principles:
- Uptrend: If the short window crosses above the long window, this suggests a potential increase in the asset's price. Therefore, we convert asset y to asset x.
- Downtrend: If the short window crosses below the long window, this suggests a potential downturn in the asset's price. Therefore, we convert asset x to asset y.
c src="/docs/moving-averages-sim1.png" alt="Moving Averages Simulation Rewards" />
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/moving_averages
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
The MovingAveragePolicy
class inherits from the BasePolicy
class. It is used to implement a moving average trading policy for a UniswapV3Environment
with a single pool.
class MovingAveragePolicy(BasePolicy):
"""Moving average trading policy for a UniswapV3Env with a single pool.
:param agent: The agent which is using this policy.
:param short_window: The short window length for the moving average.
:param long_window: The long window length for the moving average.
"""
def __init__(self, agent: BaseAgent, short_window: int, long_window: int) -> None:
super().__init__(agent=agent)
self._short_window = short_window
self._long_window = long_window
self.long_window = deque(maxlen=long_window)
self.short_window = deque(maxlen=short_window)
Signal Calculation
Signals allow us to easily view data on our Dojo dashboard. In this example, we are adding 2 signals: LongShortDiff
and Locked
.
The LongShortDiff
signal represents the difference between the mean of the short window and the mean of the long window.
It indicates the relationship between short-term and long-term price trends.
The Locked
signal indicates whether the strategy is ready to make trades. It is set to True
when either the short or long window is not
fully populated (meaning the strategy is not yet ready to make trading decisions). Once both windows are full, it is set to False
.
We can then add bookmarks on the dashboard to view when a trade was made and at what LongShortDiff
value.
![Moving Averages Simulation Signals](/docs/moving-averages-sim2.png)
Trade Execution
The predict
method, an abstract method in BasePolicy
, is implemented in MovingAveragePolicy
. This method defines the conditions
under which the agent should swap his assets.
When the mean of the short window is greater than the mean of the long window, this means the short window 'crosses above' the long window.
This indicates a potential uptrend so we return a UniswapV3Trade
object with the required parameters such as quantities=(Decimal(0), y_quantity)
,
agent, and pool. This swaps y tokens of the agent to x tokens, essentially buying the x asset.
Similarly, when the mean of the short windows is less than the mean of the long window, this means the short window 'crosses below' the long window.
This indicates a potential downtrend so we return a UniswapV3Trade
object with the required parameters such as quantities=(x_quantity, Decimal(0))
,
agent, and pool. This swaps x tokens of the agent to y tokens, essentially buying the y asset and selling the x asset.
if self._x_to_y_indicated(pool_tokens):
y_quantity = self.agent.quantity(pool_tokens[1])
self._clear_windows()
return [
UniswapV3Trade(
agent=self.agent,
pool=pool,
quantities=(Decimal(0), y_quantity),
)
]
To run our trading simulation, we need to create instances of agents, environments and policies so we run the run.py
file.
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.