Skip to content

Commit

Permalink
Making progress
Browse files Browse the repository at this point in the history
  • Loading branch information
miohtama committed May 25, 2022
1 parent 1626da5 commit a49a16a
Show file tree
Hide file tree
Showing 10 changed files with 186 additions and 29 deletions.
5 changes: 5 additions & 0 deletions cache/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Cache folder

Store downloaded trading data files here.


15 changes: 15 additions & 0 deletions configurations/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Executor configurations

This folder contains configuration scripts for different trading strategy executions

- Strategy Python file
- Used Python hot wallet
- Discord webhooks

These scripts are used to create `.env` file that you can use with `docker-compose` or directly `source` in shell.

The configuration is created by splicing together

- Shared secret variables (e.g. JSON-RPC endpoints)
- Strategy specific secret variables (e.g. hot wallet private key)
- Public variables (e.g. strategy icon, name and description, gas pricing parameters)
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
#!/bin/bash
#
# QuickSwap momentum trading launch script.
# QuickSwap momentum strategy configuration script.
#
# This script combines a strategy specific trade executor environt variables
# with secret environment variables before running the trade-executor command line entry point.
# This file will set up environment variables to execute the strategy,
# either for normal UNIX application run or Docker-compose run.
#
# Check that `~/secrets.env` and `~/$EXECUTOR_ID.secrets.env` are set up.
# Usage:
#
# Then run the checks:
# configurations/quickswap-momentum.sh
#
# bootstraps/polygon_momentum.sh check-universe --max-data-delay-minutes=1440
# This will generate:
#
# Then start:
#
# bootstraps/polygon_momentum.sh start
# ~/quickswap-momentum.env
#
# The strategy is mapped to a webhook in its secrets file:
#
Expand All @@ -36,7 +34,7 @@ check_secret_envs()
# This id is used in various paths and such.
# It is taken from the shell script name.
export EXECUTOR_ID=`basename "$0" .sh`
echo "Starting trade executor $EXECUTOR_ID"
echo "Creating strategy execution configuration for $EXECUTOR_ID"

# Strategy specific secrets.
# This file will give us private key needed to access the hot wallet
Expand All @@ -47,34 +45,40 @@ if [ ! -f "$STRATEGY_SECRETS_FILE" ] ; then
exit 1
fi


# Read generic secrets, then strategy specific secrets
source ~/secrets.env
source $STRATEGY_SECRETS_FILE

# These variables must come from the secrets file
check_secret_envs PRIVATE_KEY JSON_RPC_BINANCE TRADING_STRATEGY_API_KEY DISCORD_WEBHOOK_URL HTTP_ENABLED
check_secret_envs PRIVATE_KEY JSON_RPC_BINANCE JSON_RPC_POLYGON TRADING_STRATEGY_API_KEY DISCORD_WEBHOOK_URL HTTP_ENABLED

# Metadata
export NAME="Polygon momentum"
export NAME="Quickswap momentum"
export DOMAIN_NAME="robocop.tradingstrategy.ai"
export SHORT_DESCRIPTION="A data collection test that trades on Polygon MATIC/USDC pairs."
export LONG_DESCRIPTION="This strategy is a test strategy that does not aim to generated profit. The strategy trades on MATIC/USDC pairs on QuickSwap. The strategy rebalances every 16 hours to generate maximum amount of data. Based on 4h candles, the strategy calculates the momentum and picks highest gainers. The portfolio can hold 6 positions at once."
export ICON_URL="src="https://i0.wp.com/bloody-disgusting.com/wp-content/uploads/2022/01/watch-robocop-the-series.png?w=1270"
export ICON_URL="https://i0.wp.com/bloody-disgusting.com/wp-content/uploads/2022/01/watch-robocop-the-series.png?w=1270"

export STRATEGY_FILE="${PWD}/strategies/${EXECUTOR_ID}.py"
export STRATEGY_FILE="strategies/${EXECUTOR_ID}.py"

export JSON_RPC=$JSON_RPC_BINANCE
export GAS_PRICE_METHOD="legacy"
export STATE_FILE="$EXECUTOR_ID.json"
export EXECUTION_TYPE="uniswap_v2_hot_wallet"
export APPROVAL_TYPE="unchecked"
export CACHE_PATH="${PWD}/.cache/${EXECUTOR_ID}"
export CACHE_PATH="cache/${EXECUTOR_ID}"
export TICK_OFFSET_MINUTES="10"
export TICK_SIZE="16h"
export HTTP_PORT=3456

# 12 hours
export MAX_DATA_DELAY_MINUTES=720

echo "HTTP enabled is $HTTP_ENABLED"
# Passed as Docker volume mount point
export STATE_FILE=state/$EXECUTOR_ID.state.json

OUTPUT=~/$EXECUTOR_ID.env

python scripts/prepare-env.py > $OUTPUT

# https://stackoverflow.com/a/1537695/315168
poetry run trade-executor "$@"
echo "Created $OUTPUT"
20 changes: 13 additions & 7 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@
#
version: "3.9"
services:
polygon-momentum:
quickswap-momentum:
container_name: quickswap-momentum
build: .
ports:
- "10001:3456"
# Mapped in reverse proxy Caddyfile
- "127.0.0.1:10001:3456"
volumes:
- .:/state
environment:
FLASK_ENV: development
redis:
image: "redis:alpine"
# Save the strategy execution state in the local filesystem
- ./state:/usr/src/trade-executor/state
# Cache the dataset downloads in the local filesystem
- ./cache:/usr/src/trade-executor/cache
env_file:
# Generated by configurations/quickswap-momentum.sh
- ~/quickswap-momentum.env
# What we pass to tradexecutor.cli.main application
command: start
48 changes: 47 additions & 1 deletion docs/docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
- Port 3456 is exposed for the executor webhook integration
- All executor parameters must be passed as environment variables
- The application files are copied to `/usr/src/trade-executor`
- Work dir is `/usr/src/trade-executor`
- You need to configure a domain name for each strategy executions
- Local `/state` and `/cache` are mapped to `/usr/src/trade-executor` - note that these folders are **shared across instances**
and trade executor application code must deal with having specific state files for each strategy

# Building

Expand All @@ -16,9 +20,51 @@ docker build -t trading-strategy/trade-executor .

# Running

You can start `trade-executor` binary as:

```shell
docker run -ti trading-strategy/trade-executor --help
```

# Launching exeuctors
# Configuring and launching strategy executors

## Creating environment file for Docker

First you need to prepare an environment variable file that is going to be
passed to `docker-compose`. This file contains secrets and
is spliced together for multiple configuration files

- Generic secrets: `~/secrets.env`
- Strategy specific secrets: `~/quickswap-momentum.secrets.env`
- Generic options

This option splicing is done by a configuration helper script like `configurations/quickswap-momentum.sh`

```shell
# Creates ~/quickswap-momentum.env
bash configuration/quickswap-momentum.sh
```

## Launching a strategty using docker-compose

The project comes with a `docker-compose.yml` with configurations for example strategies.

Now when we have created `~/quickswap-momentum.env` we can launch the executor.

```shell
docker-compose build quickswap-momentum
docker-compose up --no-deps -d quickswap-momentum
```

This executor

- Maps a host port for the webhook access - each strategy execution gets its own port
- This port is mapped to the Internet through a Caddy reverse proxy

# Troubleshooting the container

You can do bash

```shell
docker run -it --entrypoint /bin/bash trading-strategy/trade-executor
```
34 changes: 34 additions & 0 deletions scripts/prepare-env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""Prepare environment variable list.
Because the configuration options list is so long, it is hard to manage by hand.
- Reads the current environment variable list
- Writes out cleaned up .env file to stdout
Very useful with Docker.
"""

import os

from tradeexecutor.cli.env import get_available_env_vars

vars = get_available_env_vars()

# print("Strategy execution settings are:", ", ".join(vars))

for desc in vars:
value = os.environ.get(desc.name)
print(f"# {desc.help}")
print(f"# Type: {desc.type}")
if value is not None:
print(f"{desc.name}={value}")
else:
print(f"{desc.name}=")
print()







5 changes: 5 additions & 0 deletions state/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# State files

Running strategy executors will write their state files here.


41 changes: 41 additions & 0 deletions tradeexecutor/cli/env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""Environment variable managment."""
from dataclasses import dataclass
from typing import List

from click import Context
from typer.main import get_command

from tradeexecutor.cli.main import app


@dataclass
class EnvVarDescription:
name: str
help: str
type: str


def get_available_env_vars() -> List[EnvVarDescription]:
"""Get list of environment variable configuration options for trade-executor.
:return:
List of environment variable names
"""
command = get_command(app)
start = command.commands["start"]
ctx = Context(start)
params = start.get_params(ctx)
result = []
for p in params:
envvar = p.envvar
if envvar:
# Option --help does not have envvar, etc.
result.append(
EnvVarDescription(
envvar,
p.help,
p.type,
)
)

return result
5 changes: 3 additions & 2 deletions tradeexecutor/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
import logging
from pathlib import Path
from queue import Queue
from typing import Optional
from typing import Optional, List
import pkg_resources

import typer
from click import Context
from typer.main import get_command

from tradeexecutor.ethereum.uniswap_v2_execution import UniswapV2ExecutionModel
from tradeexecutor.monkeypatch.dataclasses_json import patch_dataclasses_json
Expand Down Expand Up @@ -348,4 +350,3 @@ def check_wallet(
logger.info("%s: %s %s", details.name, details.convert_to_decimals(balance), details.symbol)



0 comments on commit a49a16a

Please sign in to comment.