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

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.

How To Run

Installation

Follow our Getting Started guide to install the dojo library and other required tools.

Then clone the dojo_examples repository on GitHub using the following command on your terminal.

Terminal
git clone https://github.com/CompassLabs/dojo_examples.git

Go into the moving_averages directory to run our strategy.

Terminal
cd dojo_examples/examples/moving_averages

Running

Run the dojo_examples/start_dashboard.py script inside the demo folder using the following command if you would like to access your dashboard.

Terminal
python start_dashboard.py

On another terminal window, copy the following command in the dojo_examples/examples/moving_averages folder.

Terminal
python run.py

This command will setup your local blockchain, contracts, accounts and agents. You can then access your Dojo dashboard at http://localhost:8051.


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 UniV3Env with a single pool.

policy.py
class MovingAveragePolicy(BasePolicy):
  """Moving average trading policy for a UniV3Env 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.

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 UniV3Trade 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 UniV3Trade 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.

policy.py
if self._x_to_y_indicated(pool_tokens):
  y_quantity = self.agent.quantity(pool_tokens[1])
  self._clear_windows()
  return [
      UniV3Trade(
          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.