Operating a Live pysystemtrade System: Data, Orders, and Monitoring
Summary
This documentation explains the production workflow for pysystemtrade, from obtaining market prices and generating desired positions to sending orders and reconciling accounting information. It covers the production system’s components and data flow, broker connections, data storage and backups, configuration management, logging, reporting, and operational scripts. A substantial portion follows orders through strategy, contract, and broker levels, including fills, position updates, roll handling, manual trades, and order completion.
The guide also discusses deployment choices, process monitoring, interactive controls, and reports such as slippage and trading costs. It is operational guidance for running the software, rather than a trading strategy or evidence that any system is profitable. Its procedures depend on the user’s broker, data setup, and configuration, and the document warns that leveraged live trading can result in substantial losses; backtest results do not establish future performance.
Key ideas
- A live system coordinates price collection, target generation, order execution, and accounting.
- Orders move through strategy, contract, and broker levels, with fills updating positions and order records.
- Production operation includes data storage and backups, logging, monitoring, and reporting.
- Scripts and interactive controls support recurring data updates, order generation, execution, and manual adjustments.
- Operational instructions do not demonstrate strategy profitability, and live trading can produce losses.
Tags
Full text
# production
This document is specifically about using pysystemtrade for *live production trading*.
This includes:
1. Getting prices
2. Generating desired trades
3. Executing trades
4. Getting accounting information
Related documents (which you should read before this one!):
- [Backtesting with pysystemtrade](/docs/backtesting.md)
- [Storing futures and spot FX data](/docs/data.md)
- [Connecting pysystemtrade to interactive brokers](/docs/IB.md)
And documents you should read after this one:
- [Instruments](/docs/instruments.md)
- [Dashboard and monitor](/docs/dashboard_and_monitor.md)
- [Production strategy changes](/docs/production_strategy_changes.md)
*IMPORTANT: Make sure you know what you are doing. All financial trading offers the possibility of loss. Leveraged trading, such as futures trading, may result in you losing all your money, and still owing more. Backtested results are no guarantee of future performance. No warranty is offered or implied for this software. I can take no responsibility for any losses caused by live trading using pysystemtrade. Use at your own risk.*
Table of Contents
=================
* [Table of Contents](#table-of-contents)
* [Quick start guide](#quick-start-guide)
* [Production system data flow](#production-system-data-flow)
* [Overview of a production system](#overview-of-a-production-system)
* [Implementation options](#implementation-options)
* [Automation options](#automation-options)
* [Machines, containers and clouds](#machines-containers-and-clouds)
* [Backup machine](#backup-machine)
* [Multiple systems](#multiple-systems)
* [Code and configuration management](#code-and-configuration-management)
* [Managing your separate directories of code and configuration](#managing-your-separate-directories-of-code-and-configuration)
* [Managing your private directory](#managing-your-private-directory)
* [Custom private directory](#custom-private-directory)
* [Finalise your backtest configuration](#finalise-your-backtest-configuration)
* [Linking to a broker](#linking-to-a-broker)
* [Other data sources](#other-data-sources)
* [Data storage](#data-storage)
* [Arctic](#arctic)
* [Using Arctic in production instead of Parquet](#using-arctic-in-production-instead-of-parquet)
* [Data backup](#data-backup)
* [MongoDB data](#mongodb-data)
* [Parquet data](#parquet-data)
* [MongoDB / CSV data](#mongodb--csv-data)
* [Echos, Logging, diagnostics and reporting](#echos-logging-diagnostics-and-reporting)
* [Echos: stdout output](#echos-stdout-output)
* [Cleaning old echo files](#cleaning-old-echo-files)
* [Logging](#logging)
* [socket](#socket)
* [socket server as a service](#socket-server-as-a-service)
* [console](#console)
* [email](#email)
* [Adding logging to your code](#adding-logging-to-your-code)
* [Examples](#examples)
* [Cleaning old logs](#cleaning-old-logs)
* [Echos](#echos)
* [Logs](#logs)
* [psysystemtrade reports](#psysystemtrade-reports)
* [Positions and order levels](#positions-and-order-levels)
* [Instrument level](#instrument-level)
* [Contract level](#contract-level)
* [Broker level](#broker-level)
* [The journey of an order](#the-journey-of-an-order)
* [Optimal positions](#optimal-positions)
* [Optimal position for roll orders](#optimal-position-for-roll-orders)
* [Strategy order handling](#strategy-order-handling)
* [Instrument orders in detail:](#instrument-orders-in-detail)
* [Strategy order handling for roll orders](#strategy-order-handling-for-roll-orders)
* [Overrides](#overrides)
* [Stack handler](#stack-handler)
* [Contract order creation](#contract-order-creation)
* [Contract order creation - normal orders](#contract-order-creation---normal-orders)
* [Contract order creation - passive roll status](#contract-order-creation---passive-roll-status)
* [Instrument and contract order creation - active roll orders](#instrument-and-contract-order-creation---active-roll-orders)
* [Manual trades](#manual-trades)
* [Broker order creation and execution](#broker-order-creation-and-execution)
* [Before an order is traded](#before-an-order-is-traded)
* [Trading algos](#trading-algos)
* [Pre-order preparation in the trading algo.](#pre-order-preparation-in-the-trading-algo)
* [Broker order characteristics](#broker-order-characteristics)
* [Order execution in the sysbroker code](#order-execution-in-the-sysbroker-code)
* [Adding the broker trade to the database](#adding-the-broker-trade-to-the-database)
* [Managing the trade](#managing-the-trade)
* [After execution: fills and completions](#after-execution-fills-and-completions)
* [Fills and completions](#fills-and-completions)
* [Broker order fills](#broker-order-fills)
* [An aside, what happens if fills happen later?](#an-aside-what-happens-if-fills-happen-later)
* [Contract order fills and position updates](#contract-order-fills-and-position-updates)
* [Instrument order fills and position updates](#instrument-order-fills-and-position-updates)
* [Single contract order / single leg](#single-contract-order--single-leg)
* [Single contract order / multiple legs (eg spread trade)](#single-contract-order--multiple-legs-eg-spread-trade)
* [Multiple contract orders](#multiple-contract-orders)
* [Order completions](#order-completions)
* [Order deactivation](#order-deactivation)
* [Adding to historic order databases](#adding-to-historic-order-databases)
* [End of day stack shut down process](#end-of-day-stack-shut-down-process)
* [Historic order tables and trade reporting](#historic-order-tables-and-trade-reporting)
* [Scripts](#scripts)
* [Script calling](#script-calling)
* [Script naming convention](#script-naming-convention)
* [Run processes](#run-processes)
* [Core production system components](#core-production-system-components)
* [Get spot FX data from interactive brokers, write to Parquet (Daily)](#get-spot-fx-data-from-interactive-brokers-write-to-parquet-daily)
* [Update sampled contracts (Daily)](#update-sampled-contracts-daily)
* [Update futures contract historical price data (Daily)](#update-futures-contract-historical-price-data-daily)
* [A note on market data subscriptions](#a-note-on-market-data-subscriptions)
* [Set times when different regions download prices](#set-times-when-different-regions-download-prices)
* [Update multiple and adjusted prices (Daily)](#update-multiple-and-adjusted-prices-daily)
* [Update capital and P&L by polling brokerage account](#update-capital-and-pl-by-polling-brokerage-account)
* [Allocate capital to strategies](#allocate-capital-to-strategies)
* [Run updated backtest systems for one or more strategies](#run-updated-backtest-systems-for-one-or-more-strategies)
* [Generate orders for each strategy](#generate-orders-for-each-strategy)
* [Execute orders](#execute-orders)
* [Interactive scripts to modify data](#interactive-scripts-to-modify-data)
* [Manual check of futures contract historical price data](#manual-check-of-futures-contract-historical-price-data)
* [Manual check of FX price data](#manual-check-of-fx-price-data)
* [Interactively modify capital values](#interactively-modify-capital-values)
* [Interactively roll adjusted prices](#interactively-roll-adjusted-prices)
* [Manually input instrument codes and manually decide when to roll](#manually-input-instrument-codes-and-manually-decide-when-to-roll)
* [Cycle through instrument codes automatically, but manually decide when to roll](#cycle-through-instrument-codes-automatically-but-manually-decide-when-to-roll)
* [Cycle through instrument codes automatically, auto decide when to roll, manually confirm rolls](#cycle-through-instrument-codes-automatically-auto-decide-when-to-roll-manually-confirm-rolls)
* [Cycle through instrument codes automatically, auto decide when to roll, automatically roll](#cycle-through-instrument-codes-automatically-auto-decide-when-to-roll-automatically-roll)
* [Menu driven interactive scripts](#menu-driven-interactive-scripts)
* [Interactive controls](#interactive-controls)
* [Trade limits](#trade-limits)
* [Position limits](#position-limits)
* [Trade control / override](#trade-control--override)
* [Broker client IDs](#broker-client-ids)
* [Process control & monitoring](#process-control--monitoring)
* [View processes](#view-processes)
* [Change status of process](#change-status-of-process)
* [Global status change](#global-status-change)
* [Mark as close](#mark-as-close)
* [Mark all dead processes as close](#mark-all-dead-processes-as-close)
* [View process configuration](#view-process-configuration)
* [Update configuration](#update-configuration)
* [Interactive diagnostics](#interactive-diagnostics)
* [Backtest objects](#backtest-objects)
* [Output choice](#output-choice)
* [Choice of strategy and backtest](#choice-of-strategy-and-backtest)
* [Choose stage / method / arguments](#choose-stage--method--arguments)
* [Alternative Python code](#alternative-python-code)
* [Instrument configuration](#instrument-configuration)
* [View instrument configuration data](#view-instrument-configuration-data)
* [View contract configuration data](#view-contract-configuration-data)
* [View trading hours for all instruments](#view-trading-hours-for-all-instruments)
* [Emails](#emails)
* [View stored emails](#view-stored-emails)
* [View prices](#view-prices)
* [View capital](#view-capital)
* [Positions and orders](#positions-and-orders)
* [Reports](#reports)
* [Interactive order stack](#interactive-order-stack)
* [View](#view)
* [Create orders](#create-orders)
* [Spawn contract orders from instrument orders](#spawn-contract-orders-from-instrument-orders)
* [Create force roll contract orders](#create-force-roll-contract-orders)
* [Create (and try to execute...) IB broker orders](#create-and-try-to-execute-ib-broker-orders)
* [Balance trade: Create a series of trades and immediately fill them (not actually executed)](#balance-trade-create-a-series-of-trades-and-immediately-fill-them-not-actually-executed)
* [Balance instrument trade: Create a trade just at the strategy level and fill (not actually executed)](#balance-instrument-trade-create-a-trade-just-at-the-strategy-level-and-fill-not-actually-executed)
* [Manual trade: Create a series of trades to be executed](#manual-trade-create-a-series-of-trades-to-be-executed)
* [Cash FX trade](#cash-fx-trade)
* [Netting, cancellation and locks](#netting-cancellation-and-locks)
* [Cancel broker order](#cancel-broker-order)
* [Net instrument orders](#net-instrument-orders)
* [Lock/unlock order](#lockunlock-order)
* [Lock/unlock instrument code](#lockunlock-instrument-code)
* [Unlock all instruments](#unlock-all-instruments)
* [Remove Algo lock on contract order](#remove-algo-lock-on-contract-order)
* [Delete and clean](#delete-and-clean)
* [Delete entire stack (CAREFUL!)](#delete-entire-stack-careful)
* [Delete specific order ID (CAREFUL!)](#delete-specific-order-id-careful)
* [End of day process (cancel orders, mark all orders as complete, delete orders)](#end-of-day-process-cancel-orders-mark-all-orders-as-complete-delete-orders)
* [Reporting, housekeeping and backup scripts](#reporting-housekeeping-and-backup-scripts)
* [Run all reports](#run-all-reports)
* [Delete old pickled backtest state objects](#delete-old-pickled-backtest-state-objects)
* [Clean up old logs](#clean-up-old-logs)
* [Truncate echo files](#truncate-echo-files)
* [Backup DB to CSV files](#backup-db-to-csv-files)
* [Backup state files](#backup-state-files)
* [Backup MongoDB dump](#backup-mongodb-dump)
* [Backup Parquet](#backup-parquet)
* [Start up script](#start-up-script)
* [Scripts under other (non-linux) operating systems](#scripts-under-other-non-linux-operating-systems)
* [Scheduling](#scheduling)
* [Issues to consider when constructing the schedule](#issues-to-consider-when-constructing-the-schedule)
* [Choice of scheduling systems](#choice-of-scheduling-systems)
* [Linux cron](#linux-cron)
* [Third party scheduler](#third-party-scheduler)
* [Windows task scheduler](#windows-task-scheduler)
* [Python](#python)
* [Manual system](#manual-system)
* [Hybrid of Python and cron](#hybrid-of-python-and-cron)
* [Pysystemtrade scheduling](#pysystemtrade-scheduling)
* [Configuring the scheduling](#configuring-the-scheduling)
* [The crontab](#the-crontab)
* [Process configuration](#process-configuration)
* [System monitor and dashboard](#system-monitor-and-dashboard)
* [Troubleshooting?](#troubleshooting)
* [Production system concepts](#production-system-concepts)
* [Configuration files](#configuration-files)
* [System defaults & Private config](#system-defaults--private-config)
* [System backtest YAML config file(s)](#system-backtest-yaml-config-files)
* [Control config files](#control-config-files)
* [Broker and data source specific configuration files](#broker-and-data-source-specific-configuration-files)
* [Instrument and roll configuration](#instrument-and-roll-configuration)
* [Set up configuration](#set-up-configuration)
* [Trading hours configuration](#trading-hours-configuration)
* [Capital](#capital)
* [Large changes in capital](#large-changes-in-capital)
* [Withdrawals and deposits of cash or stock](#withdrawals-and-deposits-of-cash-or-stock)
* [Change in capital methodology or capital base](#change-in-capital-methodology-or-capital-base)
* [Strategies](#strategies)
* [Strategy capital](#strategy-capital)
* [Risk target](#risk-target)
* [Changing risk targets and/or capital](#changing-risk-targets-andor-capital)
* [System runner](#system-runner)
* [Strategy order generator](#strategy-order-generator)
* [Load backtests](#load-backtests)
* [Reporting code](#reporting-code)
* [Recovering from a crash - what you can save and how, and what you can't](#recovering-from-a-crash---what-you-can-save-and-how-and-what-you-cant)
* [General advice](#general-advice)
* [Data recovery](#data-recovery)
* [Reporting](#reporting)
* [Dashboard](#dashboard)
* [Roll report (Daily)](#roll-report-daily)
* [P&L report](#pl-report)
* [Status report](#status-report)
* [Trade report](#trade-report)
* [Reconcile report](#reconcile-report)
* [Strategy report](#strategy-report)
* [Risk report](#risk-report)
* [Liquidity report](#liquidity-report)
* [Costs report](#costs-report)
* [TODO add new reports](#todo-add-new-reports)
* [Customize scheduled report generation](#customize-scheduled-report-generation)
Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc)
# Quick start guide
This 'quick' start guide assumes the following:
- you are running on a linux box with an appropriate distro (I use Mint). Windows / Mac people will have to do some things slightly differently
- you are using interactive brokers
- you are storing data using MongoDB
- you have a backtest that you are happy with
- you are happy to store your data and configuration in the /private directory of your pysystemtrade installation
You need to:
- Read this document very thoroughly!
- Prerequisites:
- Install [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git), install or update [python3](https://docs.python-guide.org/starting/install3/linux/). You may also find a simple text editor (like emacs) is useful for fine-tuning, and if you are using a headless server then [x11vnc](http://www.karlrunge.com/x11vnc/) is helpful.
- Add the following environment variables to your `~/.profile`: (feel free to use other directories):
- MONGO_DATA=/home/user_name/data/mongodb/
- PYSYS_CODE=/home/user_name/pysystemtrade
- SCRIPT_PATH=/home/user_name/pysystemtrade/sysproduction/linux/scripts
- ECHO_PATH=/home/user_name/echos
- MONGO_BACKUP_PATH=/media/shared_network/drive/mongo_backup
- Add the SCRIPT_PATH directory to your PATH
- Create the following directories (again use other directories if you like, but you must modify the .profile above and specify the proper directories in `private_config.yaml`)
- '/home/user_name/data/mongodb/'
- '/home/user_name/data/parquet'
- '/home/user_name/echos/'
- '/home/user_name/data/mongo_dump'
- '/home/user_name/data/backups_csv'
- '/home/user_name/data/backtests'
- '/home/user_name/data/reports'
- Install the pysystemtrade package, and install or update, any dependencies in directory $PYSYS_CODE (it's possible to put it elsewhere, but you will need to modify the environment variables listed above). If using git clone from your home directory this should create the directory '/home/user_name/pysystemtrade/'
- [Set up interactive brokers](/docs/IB.md), get a gateway running.
- [Install MongoDB](https://docs.mongodb.com/manual/administration/install-on-linux/).
- create a file `private_config.yaml` in the private directory of [pysystemtrade](/private), and optionally a [`private_control_config.yaml` file in the same directory](#process-configuration) See [here for more details](#system-defaults--private-config)
- if you are located anywhere other than GMT, then you must adjust the trading hours for your timezone. See [here](#trading-hours-configuration)
- Set `parquet_store` in 'private_config.yaml' to the Parquet directory you set up earlier
- [check a MongoDB server is running with the right data directory](/docs/data.md#mongodb) command line: `mongod --dbpath $MONGO_DATA`
- launch an IB gateway (this could be done automatically depending on your security setup)
- FX data:
- [Initialise the spot FX data from CSV files](/sysinit/futures/repocsv_spotfx_prices.py) (this will be out of date, but you will update it in a moment)
- Update the FX price data using interactive brokers: command line:`. /home/your_user_name/pysystemtrade/sysproduction/linux/scripts/update_fx_prices`
- Instrument configuration:
- Set up futures instrument spread costs using this script [repocsv_spread_costs.py](/sysinit/futures/repocsv_spread_costs.py).
- Futures contract prices:
- [You must have a source of individual futures prices, then backfill them into Parquet](/docs/data.md#getting-historical-data-for-individual-futures-contracts).
- Roll calendars:
- [Create roll calendars for each instrument you are trading](/docs/data.md#roll-calendars)
- [Ensure you are sampling all the contracts you want to sample](#update-sampled-contracts-daily)
- Adjusted futures prices:
- [Create multiple prices in Parquet](/docs/data.md#creating-and-storing-multiple-prices).
- [Create adjusted prices in Parquet](/docs/data.md#creating-and-storing-back-adjusted-prices)
- Use [interactive diagnostics](#interactive-diagnostics) to check all your prices are in place correctly
- Live production backtest:
- Create a YAML config file to run the live production 'backtest'. For speed, I recommend you do not estimate parameters, but use fixed parameters, using the [yaml_config_with_estimated_parameters method of systemDiag](/systems/diagoutput.py) function to output these to a YAML file.
- Scheduling:
- Initialise the [supplied crontab](/sysproduction/linux/crontab). Note if you have put your code or echos somewhere else you will need to modify the directory references at the top of the crontab.
- All scripts executable by the crontab need to be executable, so do the following: `cd $SCRIPT_PATH` ; `sudo chmod +x *.*`
- Consider adding [position and trade limits](#interactive-controls)
- Review the [configuration options](#configuration-files) available
Before trading, and each time you restart the machine you should:
- [check a MongoDB server is running with the right data directory](/docs/data.md#mongodb) command line: `mongod --dbpath $MONGO_DATA` (the supplied crontab should do this)
- launch an IB gateway (this could [be done automatically](https://github.com/IbcAlpha/IBC) depending on your security setup)
- ensure all processes are [marked as 'close'](#mark-as-close)
Note that the system won't start trading until the next day, unless you manually launch the processes that would ordinarily have been started by the crontab or other [scheduler](#scheduling). [Linux screen](https://linuxize.com/post/how-to-use-linux-screen/) is helpful if you want to launch a process but not keep the window active (eg on a headless machine).
Also see [this](#recovering-from-a-crash---what-you-can-save-and-how-and-what-you-cant) on recovering from a crash (a system crash that is, not a market crash. You're on your own with the latter).
When trading you will need to do the following:
- Check [reports ](#reporting)
- [Roll instruments](#interactively-roll-adjusted-prices)
- Ad-hoc [diagnostics and controls](#menu-driven-interactive-scripts)
- [Manually check](#interactive-scripts-to-modify-data) large price changes
# Production system data flow
*[Update FX prices]()*
*[Update roll adjusted prices](#get-spot-fx-data-from-interactive-brokers-write-to-parquet-daily)*
*[Update sampled contracts](#update-sampled-contracts-daily)*
*[Update historical prices](#update-futures-contract-historical-price-data-daily)*
*[Update multiple adjusted prices](#update-multiple-and-adjusted-prices-daily)*
*[Update account values](#update-capital-and-pl-by-polling-brokerage-account)*
*[Update strategy capital](#allocate-capital-to-strategies)*
*[Update system backtests](#run-updated-backtest-systems-for-one-or-more-strategies)*
*[Update strategy orders](#generate-orders-for-each-strategy)*
*[Run stack handler](#execute-orders)*
# Overview of a production system
Here are the steps you need to follow to set up a production system. I assume you already have a backtested system in pysystemtrade, with appropriate Python libraries etc.
1. Consider your implementation options
2. Ensure you have a private area for your system code and configuration
3. Finalise and store your backtested system configuration
4. If you want to automatically execute, or get data from a broker, then set up a broker
5. Set up any other data sources you need.
6. Set up a database for storage, including a backup
7. Have a strategy for reporting, diagnostics, and logs
8. Write some scripts to kick off processes to: get data, get accounting information, calculate optimal positions, execute trades, run reports, and do backups and housekeeping.
9. Schedule your scripts to run regularly
10. Regularly monitor your system, and deal with any problems
## Implementation options
Standard implementation for pysystemtrade is a fully automated system running on a single local machine. In this section I briefly describe some alternatives you may wish to consider.
My own implementation runs on a Linux machine, and some of the implementation details in this document are Linux specific. Windows and Mac users are welcome to contribute with respect to any differences.
### Automation options
You can run pysystemtrade as a fully automated system, which does everything from getting prices through to executing orders.
If running fully automated, [IBC](https://github.com/IbcAlpha/IBC) is very useful. But other patterns make sense. In particular, you may wish to do your trading manually, after pulling in prices and generating optimal positions manually. It will also be possible to trade manually, but allow pysystemtrade to pick up your fills from the broker rather than entering them manually. For example, you might not trust the system (I wouldn't blame you), it gives you more control, you might think your execution is better than an algo, you might be doing some testing, or you simply want to use a broker that doesn't offer an API.
I suggest the following:
- From `run_stack_handler` process configuration in your `private_control_config.yaml` file, remove the method `create_broker_orders_from_contract_orders`
- Run `interactive_order_stack` to check what contract orders have been created.
- Do the trade
- Use 'manually fill broker or contract order' in `interactive_order_stack` to enter the fill details.
Everything else should be allowed to run as normal.
### Machines, containers and clouds
Pysystemtrade can be run locally in the normal way, on a single machine. But you may also want to consider containerisation (see [my blog post](https://qoppac.blogspot.com/2017/01/playing-with-docker-some-initial.html)), or even implementing on AWS or another cloud solution. You could also spread your implementation across several local machines.
If spreading your implementation across several machines bear in mind:
- Interactive brokers
- interactive brokers Gateway will need to have the ip address of all relevant machines that connect to it in the whitelist
- you will need to modify the `private_config.yaml` system configuration file, so it connects to a different IP address `ib_ipaddress: '192.168.0.10'`
- Mongodb
- Add an ip address to the `bind_ip` line in the `/etc/mongod.conf` file to allow connections from other machines `eg bind_ip=localhost, 192.168.0.10`
- You may need to change your firewall settings, either UFW (`sudo ufw enable`, `sudo ufw allow 27017 from 192.168.0.10`) or iptables
- you will need to modify the `private_config.yaml` system configuration file, so it connects to a different IP address `mongo_host: 192.168.0.13`
- you may want to enforce [further security protocol](https://docs.mongodb.com/manual/administration/security-checklist/)
- [Process configuration](#process-configuration); you will want to specify different machine names for each process in your private YAML config file.
### Backup machine
If you are running your implementation locally, or on a remote server that is not a cloud, then you should seriously consider a backup machine. The backup machine should have an up-to-date environment containing all the relevant applications, code and libraries, and on a regular basis you should update the local data stored on that machine (see [backup](#data-backup)). The backup machine doesn't need to be turned on at all times, unless you are trading in such a way that a one-hour period without trading would be critical (in my experience, one hour is the maximum time to get a backup machine online assuming the code is up-to-date, and the data is less than 24 hours stale). I also encourage you to perform a scheduled 'failover' on regular basis: stop the live machine running (best to do this at a weekend), copy across any data to the backup machine, start up the backup machine. The live machine then becomes the backup.
### Multiple systems
You may want to run multiple trading systems on a single machine. Common use cases are:
- You want to run relative value systems *
- You want different systems for different time frames (eg intraday and slower trading) *
- You want different systems for different asset classes eg stocks and ETFs, or futures
- You want to run the same system, but for different trading accounts (pysystemtrade can't handle multiple accounts natively)
- You want a paper trading and live trading system
*for these cases I plan to implement functionality in pysystemtrade so that it can handle them in the same system.
To handle this I suggest having multiple copies of the pysystemtrade environment. You will have a single crontab, but you will need multiple script, echos and other directories. You will need to change the private config file, so it points to different MongoDB database names. If you don't want multiple copies of certain data (eg prices) then you should hard code the database_name in the relevant files whenever a connection is made eg mongo_db = mongoDb(database_name='whatever'). See storing futures and spot FX data for more detail.
Finall, you should set the field `ib_idoffset` in the private config file `private/private_config.yaml` so that there is no chance of duplicate clientid connections; setting one system to have an id offset of 1, the next offset 1000, and so on should be sufficient.
## Code and configuration management
Your trading strategy will consist of pysystemtrade, plus some specific configuration files, plus possibly some bespoke code. You can either implement this as:
- separate environment, pulling in pysystemtrade as a 'yet another library'
- everything in pysystemtrade, with all specific code and configuration in the 'private' directory that is excluded from git uploads.
Personally I prefer the latter as it makes a neat self-contained unit, but this is up to you.
### Managing your separate directories of code and configuration
I strongly recommend that you use a code repo system or similar to manage your non pysystemtrade code and configuration. Since code and configuration will mostly be in text (or text like) YAML files a code repo system like git will work just fine. I do not recommend storing configuration in database files that will need to be backed up separately, because this makes it more complex to store old configuration data that can be archived and retrieved if required.
### Managing your private directory
Since the private directory is excluded from the git system (since you don't want it appearing on GitHub!), you need to ensure it is managed separately. I have a separate repo for my private stuff, for which I have a local clone in directory ~/private. Incidentally, GitHub are now offering free private repos, so that is another option.
I then use a bash script which I run in lieu of a normal git add/ commit / push cycle, to commit both private and public code:
```
# pass commit quote as an argument
# For example:
# mygitpush "this is a commit description string"
#
# copy the contents of the private directory to another, git controlled, directory
#
# we use rsync so we can exclude the git directory; which will screw things up as there is already one there
#
rsync -av ~/pysystemtrade/private/ ~/private --exclude .git
#
# git add/commit/push cycle on the main pysystemtrade directory
#
cd ~/pysystemtrade/
git add -A
git commit -m "$1"
git push
#
# git add/commit/push cycle on the copied private directory
#
cd ~/private/
git add -A
git commit -m "$1"
git push
```
A second script is run instead of a git pull:
```
# git pull within git controlled private directory copy
cd ~/private/
git pull
# copy the updated contents of the private directory to pysystemtrade private directory
# use rsync to avoid overwriting git metadata
rsync -av ~/private/ ~/pysystemtrade/private --exclude .git
# git pull from main pysystemtrade GitHub repo
cd ~/pysystemtrade/
git pull
```
### Custom private directory
If you prefer to keep your private config outside the *pysystemtrade* directory structure, this is possible too. Set
the environment variable `PYSYS_PRIVATE_CONFIG_DIR` with the full path to the custom directory:
```
PYSYS_PRIVATE_CONFIG_DIR=/home/user_name/private_custom_dir
```
or to set a custom config directory in the context of a single script
```
PYSYS_PRIVATE_CONFIG_DIR=/home/user_name/private_custom_dir python sysproduction/whatever.py
```
## Finalise your backtest configuration
You can just re-run a full daily backtest to generate your positions. This will probably mean that you end up refitting parameters like instrument weights and forecast scalars. This is pointless, slow, a waste of time, and potentially dangerous. Instead, I'd suggest using fixed values for all fitted parameters in a live trading system.
The following convenience function will take your backtested system, and create a dict which includes fixed values for all estimated parameters:
```python
# Assuming futures_system already contains a system which has estimated values
from systems.diagoutput import systemDiag
sysdiag = systemDiag(system)
sysdiag.yaml_config_with_estimated_parameters('someyamlfile.yaml',
attr_names=['forecast_scalars',
'forecast_weights',
'forecast_div_multiplier',
'forecast_mapping',
'instrument_weights',
'instrument_div_multiplier'])
```
Change the list of attr_names depending on what you want to output. You can then merge the resulting YAML file into your production backtest YAML file.
Don't forget to turn off the flags for `use_forecast_div_mult_estimates`, `use_forecast_scale_estimates`, `use_forecast_weight_estimates`, #`use_instrument_div_mult_estimates`, and `use_instrument_weight_estimates`. You don't need to change flag for forecast mapping, since this isn't done by default.
## Linking to a broker
You are probably going to want to link your system to a broker, to do one or more of the following things:
- get prices
- get account value and profitability
- do trades
- get trade fills
... although one or more of these can also be done manually.
You should now read [connecting pysystemtrade to interactive brokers](/docs/IB.md). The fields `broker_account`,`ib_ipaddress`, `ib_port` and `ib_idoffset` should be set in the private config file.
## Other data sources
You might get all your data from your broker, but there are good reasons to get data from other sources as well:
- multiple sources can improve accuracy
- multiple sources can provide redundancy in case of feed issues
- you can't get the relevant data from your broker
- the relevant data is cheaper elsewhere
You should now read [getting and storing futures and spot FX data](/docs/data.md) for some hints on writing API layers for other data sources.
## Data storage
Various kinds of data files are used by the pysystemtrade production system. Broadly speaking they fall into the following categories:
- accounting (calculations of profit and loss)
- diagnostics
- prices (see [storing futures and spot FX data](/docs/data.md))
- positions
- other state and control information
- static configuration files
The default option is to store these all into a MongoDB database, except for configuration files which are stored as YAML and CSV files. Time series data is stored in [Parquet](https://parquet.apache.org/) files. Databases used will be named with the value of parameter `mongo_db` in private config.
### Arctic
Early versions of this project used [Arctic](https://github.com/manahl/arctic) for storing time series data instead of Parquet, now deprecated. There is more detail in the [backtesting guide](/docs/backtesting.md#arctic)
#### Using Arctic in production instead of Parquet
It is still possible to use the older method. For production, modify the classes assigned in `sysproduction.data.production_data_objects.py` to point to the Arctic classes instead of Parquet:
```python
use_production_classes = {
FX_DATA: arcticFxPricesData,
ROLL_PARAMETERS_DATA: csvRollParametersData,
FUTURES_INSTRUMENT_DATA: csvFuturesInstrumentData,
FUTURES_CONTRACT_DATA: mongoFuturesContractData,
STORED_SPREAD_DATA: mongoSpreadCostData,
FUTURES_CONTRACT_PRICE_DATA: arcticFuturesContractPriceData,
FUTURES_MULTIPLE_PRICE_DATA: arcticFuturesMultiplePricesData,
FUTURES_ADJUSTED_PRICE_DATA: arcticFuturesAdjustedPricesData,
CAPITAL_DATA: arcticCapitalData,
CONTRACT_POSITION_DATA: arcticContractPositionData,
STRATEGY_POSITION_DATA: arcticStrategyPositionData,
OPTIMAL_POSITION_DATA: arcticOptimalPositionData,
HISTORIC_SPREAD_DATA: arcticSpreadsForInstrumentData,
STRATEGY_HISTORIC_ORDERS_DATA: mongoStrategyHistoricOrdersData,
CONTRACT_HISTORIC_ORDERS_DATA: mongoContractHistoricOrdersData,
BROKER_HISTORIC_ORDERS_DATA: mongoBrokerHistoricOrdersData,
INSTRUMENT_ORDER_STACK_DATA: mongoInstrumentOrderStackData,
CONTRACT_ORDER_STACK_DATA: mongoContractOrderStackData,
BROKER_ORDER_STACK_DATA: mongoBrokerOrderStackData,
ROLL_STATE_DATA: mongoRollStateData,
PROCESS_CONTROL_DATA: mongoControlProcessData,
}
```
You would need to uncomment the Arctic imports too.
## Data backup
### MongoDB data
Assuming that you are using the default MongoDB for storing, then I recommend using [mongodump](https://docs.mongodb.com/manual/reference/program/mongodump/#bin.mongodump) on a daily basis to back up your files. Other more complicated alternatives are available (see the [official MongoDB man page](https://docs.mongodb.com/manual/core/backups/)). You may also want to do this if you're transferring your data to e.g. a new machine.
To avoid conflicts you should [schedule](#scheduling) your backup during the 'deadtime' for your system (see [scheduling](#scheduling)).
Linux:
```
# dumps everything into dump directory
# make sure a MongoDB instance is running with correct directory, but ideally without any load; command line: `mongod --dbpath $MONGO_DATA`
mongodump -o ~/dump/
# copy dump directory to another machine or drive. This will create a directory $MONGO_BACKUP_PATH/dump/
cp -rf ~/dump/* $MONGO_BACKUP_PATH
```
This is done by the scheduled backup process (see [scheduling](#scheduling)), and also by the script detailed [here](#backup-mongodb-dump)
Then to restore, from a linux command line:
```
cp -rf $MONGO_BACKUP_PATH/dump/ ~
# Now make sure a MongoDB instance is running with correct directory
# If required delete any existing instances of the databases. If you don't do this the results may be unpredictable...
mongo
# This starts a mongo client
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
meta_db 0.000GB
production 0.000GB
# Most likely we want to remove 'production'
> use production
> db.dropDatabase()
> exit
# Now we run the restore (back on the linux command line)
mongorestore
```
### Parquet data
Time series data stored in Parquet files can be backed up like any other file, eg
```
rsync -chavzP --stats --progress --delete /home/user/data/parquet remote_machine:/home/user/backup_dir
```
This is done as part of the default scheduled back up process, see [here](#backup-parquet)
### MongoDB / CSV data
As I am super paranoid, I also like to output all my MongoDB data into CSV files, which I then regularly backup. This will allow a system recovery, should the MongoDB files be corrupted.
This currently supports: FX, individual futures contract prices, multiple prices, adjusted prices, position data, historical trades, capital, contract meta-data, spread costs, optimal positions. Some other state information relating to the control of trading and processes is also stored in the database and this will be lost, however this can be recovered with a little work: roll status, trade limits, position limits, and overrides. Log data will also be lost; but archived [echo files](#echos-stdout-output) could be searched if necessary.
Linux script:
```
. $SCRIPT_PATH/backup_db_to_csv
```
## Echos, Logging, diagnostics and reporting
We need to know what our system is doing, especially if it is fully automated. Here are the methods by which this should be done:
- Echos of stdout output from processes that are running
- Logging output in a file, tagged with keys to identify them
- Storage of diagnostics in a database, tagged with keys to identify them
- the option to run reports both scheduled and ad-hoc, which can optionally be automatically emailed
### Echos: stdout output
The [supplied crontab](/sysproduction/linux/crontab) contains lines like this:
```
SCRIPT_PATH="$HOME:/workspace3/psystemtrade/sysproduction/linux/scripts"
ECHO_PATH="$HOME:/echos"
#
0 6 * * 1-5 $SCRIPT_PATH/updatefxprices >> $ECHO_PATH/updatefxprices.txt 2>&1
```
The above line will run the script `updatefxprices`, but instead of outputting the results to stdout they will go to `updatefxprices.txt`. These echo files are most useful when processes crash, in which case you may want to examine the stack trace. Usually however the log files will be more useful.
#### Cleaning old echo files
Over time echo files can get... large (my default position for logging is verbose). To avoid this there is a [daily cleaning process](#truncate-echo-files) which archives old echo files with a date suffix, and deletes anything more than a month old.
Note: the configuration variable echo_extension will need changing in `private_config.yaml` if you don't use .txt file extensions, otherwise cleaning won't work.
### Logging
pysystemtrade uses the [Python logging module](https://docs.python.org/3.10/library/logging.html). See the [user guide for more detail](/docs/backtesting.md#logging) about logging in sim. Python logging is powerful and flexible, and log messages can be [formatted as you like, and sent virtually anywhere](https://docs.python.org/3.10/howto/logging.html#logging-advanced-tutorial) by providing your own config. But this section describes the default provided production setup.
In production, the requirements are more complex than in sim. As well as the context relevant attributes (that we have with sim), we also need
- ability to log to the same file from different processes
- output to console for echo files
- critical level messages to trigger an email
Configure the default production setup with:
```
PYSYS_LOGGING_CONFIG=syslogging.logging_prod.yaml
```
At the client side, (pysystemtrade) there are three handlers: socket, console, and email. There is a server (separate process) for the socket handler. More details on each below
### socket
Python doesn't support more than one process writing to a file at the same time. So, on the client side, log messages are serialised and sent over the wire. A simple TCP socket server receives, de-serialises, and writes them to disk. The socket server needs to be running first. The simplest way to start it:
```
python -u $PYSYS_CODE/syslogging/server.py
```
But that would write logs to the current working directory. Probably not what you want. Instead, pass the log file path
```
python -u $PYSYS_CODE/syslogging/server.py --file /home/path/to/your/pysystemtrade.log
```
By default, the server accepts connections on port 6020. But if you want to use another
```
python -u $PYSYS_CODE/syslogging/server.py --port 6021 --file /home/path/to/your/pysystemtrade.log
```
The socket server also handles rotating the log files daily; the default setup rotates creates a new log at midnight each day, keeping the last 5 days' files. So after a week, the log directory file listing would look something like
```
-rw-r--r-- 1 user group 19944754 May 4 15:42 pysystemtrade.log
-rw-r--r-- 1 user group 19030250 Apr 24 22:16 pysystemtrade.log.2023-04-24
-rw-r--r-- 1 user group 6178163 Apr 25 22:16 pysystemtrade.log.2023-04-25
-rw-r--r-- 1 user group 9465225 Apr 26 22:16 pysystemtrade.log.2023-04-26
-rw-r--r-- 1 user group 4593885 Apr 27 16:53 pysystemtrade.log.2023-04-27
-rw-r--r-- 1 user group 4414970 May 3 22:16 pysystemtrade.log.2023-05-03
```
The server needs to be running all the time. It needs to run in the background, start up on reboot, restart automatically in case of failure, etc. So a better way to do it would be to make it a service
#### socket server as a service
There is an example Linux systemd service file provided, see `examples/logging/logging_server.service`. And a setup guide [here](https://tecadmin.net/setup-autorun-python-script-using-systemd/). Basic setup for Debian/Ubuntu is:
- create a new file at `/etc/systemd/system/logging_server.service`
- paste the example file into it
- update the paths in `ExecStart`. If using a virtual environment, make sure to use the correct path to Python
- update the `User` and `Group` values, so the log file is not owned by root
- update the path in `Environment`, if using a custom private config directory
- run the following commands to start/stop/restart etc
```
# reload daemon
sudo systemctl daemon-reload
# enable service (restart on boot)
sudo systemctl enable log_server.service
# view service status
sudo systemctl status log_server.service
# start service
sudo systemctl start log_server.service
# stop service
sudo systemctl stop log_server.service
# restart
sudo systemctl restart log_server.service
# view service log (not pysystemtrade log)
sudo journalctl -e -u log_server.service
```
### console
All log messages also get sent to console, as with sim. The supplied `crontab` entries would therefore also pipe their output to the echo files
### email
There is a special SMTP handler, for CRITICAL log messages only. This handler uses the configured pysystemtrade email settings to send those messages as emails
#### Adding logging to your code
See the [logging docs](https://docs.python.org/3.10/library/logging.html) for usage examples. There are four ways to manage context attributes:
* *overwrite* - passed attributes are merged with any existing, overwriting duplicates (the default)
* *preserve* - passed attributes are merged with any existing, preserving duplicates
* *clear* - existing attributes are cleared, passed ones added
* *temp* - passed attributes will only be used for one invocation
#### Examples
```python
# merging attributes: method 'overwrite' (default if no method supplied)
overwrite = get_logger("Overwrite", {"type": "first"})
overwrite.info("overwrite, type 'first'")
overwrite.info(
"overwrite, type 'second', stage 'one'",
method="overwrite",
type="second",
stage="one",
)
# merging attributes: method 'preserve'
preserve = get_logger("Preserve", {"type": "first"})
preserve.info("preserve, type 'first'")
preserve.info(
"preserve, type 'first', stage 'one'", method="preserve", type="second", stage="one"
)
# merging attributes: method 'clear'
clear = get_logger("Clear", {"type": "first", "stage": "one"})
clear.info("clear, type 'first', stage 'one'")
clear.info("clear, type 'second', no stage", method="clear", type="second")
clear.info("clear, no attributes", method="clear")
# merging attributes: method 'temp'
temp = get_logger("temp", {"type": "first"})
temp.info("type should be 'first'")
temp.info(
"type should be 'second' temporarily",
method="temp",
type="second",
)
temp.info("type should be back to 'first'")
```
#### Cleaning old logs
##### Echos
There is some code to clean up **echo** files. This code is run automatically from the [daily cleaning process](#clean-up-old-logs).
Python:
```python
from sysproduction.clean_truncate_log_files import clean_truncate_log_files
clean_truncate_log_files()
```
It defaults to deleting anything more than 30 days old.
##### Logs
With the provided production logging config, the cleaning of **log** files is managed by the Python logging server. Default config is to keep the last 5 days of production logs. To adjust this, see [syslogging/server.py](/syslogging/server.py)
### psysystemtrade reports
Reports are run regularly to allow you to monitor the system and decide if any action should be taken. You can choose to have them emailed to you. To do this the email address, server and password *must* be set in `private_config.yaml`, as well as the address the email is being sent to (which can be the same as the sending email account):
```
email_address: "somebloke@anemailadress.com"
email_pwd: "h0Wm@nyLetter$ub$tiute$"
email_server: 'smtp.anemailadress.com'
email_to: "someotherbloke@anothermail.com"
```
Pysystemtrade will automatically try to negotiate TLS encryption when connecting to SMTP server and will resort to unencrypted communication only as a last resort.
Email reports are plain text by default. If your email client does not display
them in a fixed-width font, enable preformatted HTML in `private_config.yaml`:
```yaml
email_body_preformatted: True
```
This wraps plain-text message bodies in HTML `<pre>` tags, preserving spaces
and line breaks. HTML special characters in the original text are escaped.
The setting defaults to `False`, keeping existing plain-text email unchanged.
It applies to plain-text messages sent through `send_mail_msg`, including
reports and notifications; explicitly HTML messages and file/PDF emails are
unchanged. Restart processes that send emails after changing the configuration.
To use Google SMTP server without trusting the config file with your plain text password, you can create an 'App password' specifically for pysystemtrade:
- Go to [Manage my Google account](https://myaccount.google.com/security) and its 'Signing in to Google' subsection
- Ensure that '2-step verification' is On
- In 'App passwords' section generate a new one: Select app: Mail. Select device: Other, and name it 'pysystemtrade'. Click 'Generate' and copy the 16-character password (such as 'abcd efgh ijkl mnop').
For sending notifications via gmail to yourself, edit the config file as below:
```
email_address: "youraddress@gmail.com"
email_pwd: "abcdefghijklmnop"
email_server: 'smtp.gmail.com'
email_to: "youraddress@gmail.com"
```
Reports are run automatically every day by the [run reports](#run-all-reports) process, but you can also run ad-hoc reports in the [interactive diagnostics](#reports) tool. Ad hoc reports can be emailed or displayed on screen.
Full details of reports are given [here](#reporting).
# Positions and order levels
At this stage it's worth discussing the different kinds of positions and order levels. For abstraction and flexibility, positions and orders are at two /three levels:
- Instrument level (positions and orders)
- Contract level (positions and orders)
- Broker level (orders only)
You will see 'parent' and 'child' relationships discussed in the code: so the children of an instrument order are contract orders, and so on.
Each level has its own order 'stack' (not strictly a stack in computer science technology since there is no LIFO rule) on which active orders are held.
## Instrument level
Instrument specific orders for a particular strategy. These are generated by the process run_strategy_order_generator.
An instrument could be a general futures market, like GOLD or DAX. Importantly, no specific contract is specified (this will depend on the roll status). This level of abstraction is also used in backtesting. Hence, we create adjusted prices as the 'price' for an instrument. An instrument order could be explicit (i.e. no limit, just do this), conditional (do this if price goes to here) or include a limit (buy at this price or better). It can also come attached with execution preferences: trade as a market order (if urgent), as best you can using an algo, or as a limit order with a specific limit (which will be considered to be scaled to the adjusted price series).
We keep track of the positions allocated to each strategy and each instrument; these are updated when instrument orders are executed and filled.
## Contract level
An instrument order will be resolved into a contract order: an order for a specific contract (or intramarket contract spread, since this is also a 'tradeable instrument'). This is done by the process run_stack_handler. This could occur in a number of ways:
- For a normal single leg order, we trade the priced contract or the forward contract, or both; depending on whether we are passively rolling and whether our position is increasing or reducing (see [here](#interactively-roll-adjusted-prices) for more info about rolls)
- For a Force roll order, we create an intramarket spread between the priced and forward contract. This will also create a zero size instrument order.
- For a Force Outright roll order, we create two separate trades closing the priced and opening up in the forward. This will also create a zero size instrument order.
If an instrument order has a limit order, this is attached to the contract order, with an adjustment made if the contract traded is different from the contract used to generate the backadjusted price that the limit order will be scaled to (this will happen if you are currently passively rolling, and you trade the forward contract).
Contract orders are allocated to algorithms for execution, depending on what kind of instrument order was specified (limit, market, best-execution).
We keep track of the positions allocated to each instrument / contract combination; these are updated when instrument orders are executed and filled. They can also be compared directly to positions in the broker API.
## Broker level
A contract order will be resolved into a broker order when it is submitted to the broker. This is done by the process run_stack_handler. It's possible that a contract order will become multiple broker orders (since we might not choose to execute the whole lot, due to a lack of liquidity or a limit inside the algo that is used).
Broker orders are issued by execution algos (as allocated to the relevant contract order). They may be limit or market orders, depending on the operation of the relevant execution algo.
There are no positions at broker level, but we can compare broker level trades to trade information from the broker API.
Fills, once received from the broker API, are propagated upwards: broker orders are filled, then contract orders, and finally instrument orders.
Once all the child orders of an order are completed, then a parent order can also be completed. Completed orders are removed from the stack and put in historic order databases.
# The journey of an order
The most complex part of any trading system is the order management process. It is particularly complex in pysystemtrade, since it's designed to handle (in principle) some very complex types of trading strategy, and to trade multiple strategies. We also have the inherent complexity involved in trading futures. Let's look at the journey for a typical order. We'll consider the following:
- A normal order in a trading system. This could involve passively rolling from one contract to the next.
- A roll order which is a calendar spread (a Force roll)
- A roll order implemented as two separate trades (a Force Outright roll)
## Optimal positions
When a backtest is run (regularly by run_systems, or an ad-hoc basis by update_system_backtests) it will generate a set of *optimal position rules* for each strategy/instrument combination. There is no fixed structure for optimal positions, but some examples could be:
- A simple optimal position, eg trade until the position is +5 contracts. This used by the dynamic optimised trading system.
- A buffered optimal position, eg position should be between +10.87 and +13.32 contracts. This is what is used in the default provided backtest 'static' systems.
- A conditional optimal position, eg open a new buy if the price falls below this level, or close our current position if it goes above this level (which is what you'd use for mean reversion, with the addition of some stop orders). I plan to implement this kind of position management in a future trading system.
Optimal positions exist because it's generally expensive to run backtests even when parameters are fixed rather than being estimated, as I recommend for production systems (it's possible to generate backtests that only use a limited amount of data, which speeds things up somewhat, but this is unsatisfying).
An optimal position doesn't specify which contract or contracts the position is held in, that is determined later when a contract order is generated.
Optimal positions come with reference information attached. This is we can calculate the slippage caused by the delay between running the backtest and actually executing the order (normally in a backtest we assume this is one working day, but in production it will be less). We save:
- A reference price (basically the last price in the adjusted price series when the backtest was run)
- The contract that the price was snapshotted in (the current priced contract, which will give the same price as the adjusted price series). This is in case we trade a different contract than the price was referenced to (which we'll do if we're passively rolling, or if a roll occurred).
- A reference date/time, so we can calculate the delay in minutes between when the backtest thought we could execute, and when we actually execute.
Limit orders will also need to include a price, and a contract (in case the price that is referenced by the contract is wrong).
### Optimal position for roll orders
The concept of optimal positions doesn't exist for roll orders, since they are operating at the contract level, and optimal positions are at the instrument/strategy level.
## Strategy order handling
Either regularly (with run_strategy_order_generator) or ad-hoc (with update_strategy_orders) we generate instrument orders for each strategy. At the moment this is done daily, but for faster systems it may make sense to run it multiple times a day. The connection between the optimal positions and the orders generated depends on the type of strategy, but also what current positions are recorded in the database.
For example:
- A simple optimal position would take the difference between the current recorded position and the required optimal position, and produce a trade (not implemented).
- A buffered optimal position, eg optimal position should be between +10.87 and +13.32 contracts. If the current position is above +13 contracts; sell down to +13 (rounded). If it's currently below +11 contracts, then buy up to +11 contracts. This is what is used in the default provided backtest systems.
- A conditional optimal position would depend on price levels as well as current recorded positions. Such a system will probably need to generate strategy orders multiple times a day.
Positions once generated are put on the instrument order stack, with the following behaviour:
- if one or more orders exists for the current instrument and strategy:
- Sum up the unfilled part of the existing orders, then calculate what additional order would be needed to hit the optimal position
- For example, if the optimal position is +10, and the current position is +8, the original order would be +2. However, there is an existing order of +4, of which +3 has been filled, leaving +1 unfilled. Thus, we adjust the original order to +1.
- If the adjusted order is zero, which would be the case if the unfilled orders already came to the optimal position.
- if an order doesn't exist for the current instrument and strategy, then place the order (unless it is a zero order, which is what you'd get if the current required position was within the optimal buffer range)
Note that the above means it is vital that the recorded position and existing order fill data are updated and accessed at the same time (or at least that no fills are likely to occur while we're calculatinShown in full with attribution under the source's licence. Licence: GPL-3.0
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.