Skip to content

Autonomous stock options trader powered by NEAT (NeuroEvolution of Augmented Topologies)

License

Notifications You must be signed in to change notification settings

ChadBowman/neatrader

Repository files navigation

Neatrader 💸

Autonomous stock options trader powered by NEAT (NeuroEvolution of Augmented Topologies)

This repo is no longer actively developed or maintained. It was a way for me to experiment with my favorite machine learning algorithm and get some experience building a larger python project. I still think the underlying hypothesis is plausible in the limit of time and compute, but due to performance reasons I would rather use a modern machine learning framework, multiple neural networks for separate distinct tasks, and better high-level design.

Hypothesis

Instead of trying to predict the direction of the market like most traders, we can take a different approach by providing traders with opportunities to place bets. By using machine learning to manage risk, we can essentially become the "casino" and aim to outperform the market through many small, contra-bets. Paradoxically, if markets are efficient enough, we should not expect to do any better so a positive result would be surprising.

Stock options are the perfect instrument for this experiment due to the market being two-sided and zero-sum. There is also a very distinct trade-off between probability of profit and payout, depending on what strikes and expirations are chosen.

Fitness

Fitness is determined by calculating the total portfolio value vs the value of a buy-and-hold strategy at the end of the simulation period.

Network

By default, networks are not initially connected. Connections and new nodes must arise via mutations over time. The probabilities of forming new connections and nodes are greater than the probability of their removal.

The current inputs and outputs are present: Inputs:

  • portfolio cash
  • portfolio shares,
  • closing (end of day) price of security
  • MACD (moving average convergence/divergence)
  • MACD signal
  • MACD difference
  • Bollinger Bands mid
  • Bollinger Bands high
  • Bollinger Bands low
  • RSI (relative strength index)

Outputs:

  • Buy (currently means buyback/close short options position)
  • Hold (do nothing)
  • Sell (currently means open new short options position)
  • Delta (only used when opening new option to determine strike)
  • Theta (only used when opening new option to determine expiration)

Simulation

Each agent (128 in each population) is given 100 shares of TSLA to start and ran through a random, 90 day period from the training set. Concurrently, a completely separate dataset is used to run a cross-validation simulation. The cross-validation fitness has no impact on NEAT and is used to gauge overfitting.

An agent can only open and close a single covered-call. A covered-call is when one sells to open an options contract using their owned shares as collateral.

Only the closing prices are considered so agents may only place one trade per day. Low-frequency trading is the goal.

Data processing

Data was sourced using Thomas Yeng's etrade cache. The neatrader.preprocess module was created for importing and normalizing these data into csv files, which are then exported to the resources module.

Installation

Docker

docker pull chadbowman0/neatrader:latest

Local

First, clone neatrader and neat-python:

git clone git@github.com:ChadBowman/neatrader.git ~/neatrader
git clone git@github.com:ChadBowman/neat-python.git ~/neat-python

Create a virtual environment and install neat-python:

python3 -m venv ~/neatrader/env && source ~/neatrader/env/bin/activate
python3 -m pip install --upgrade pip ~/neat-python

Install neatrader:

python3 -m pip install ~/neatrader

Execution

generations per iteration (int) is optional. Omit if you just want to see some plots and results quickly. Set to a larger number for better results.

Docker

docker run chadbowman0/neatrader:latest <generations per iteration>

Local

python3 -m neatrader <generations per iteration>

To run tests:

python3 -m nose -v --nocapture --logging-level=INFO

Results

Generational performance is continually printed to the output. After every 3 (configurable) generations, plots are created which give visual representation to the winning network, population species, average/best fitness, and the winning agent's simulated trades for a new random, 90 day period. Unfortunately, the species and fitness graphs are not that interesting due to only having 3 generations per iteration. Increase this number if you want to see this improved and leverage other functionalities from NEAT.

Here are some examples:

Network network plot

Fitness average/best fitness

Speciation speciation

Example trades of best network trades

About

Autonomous stock options trader powered by NEAT (NeuroEvolution of Augmented Topologies)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published