Building a trend-following forex trading platform

Suppose from the forex tick data collected, we resample the time series at regular intervals. The average of prices over a reasonably short time period and long time period are calculated. The beta of the price series is taken as the ratio of the short-term average prices to the long-term average prices. In price series, where there is no trend, the ratio is 1—short-term prices are equal to the long-term prices. When prices are on an uptrend, the short-term prices are higher than the long-term average price levels and the beta is more than 1. Conversely, when prices are on a downtrend, the beta is less than 1.

In this section, we will discuss the implementation of a trend-following trading system to buy a position when prices are in an uptrend and sell when prices are going downtrend.

Setting up the main program

Let's create a class named ForexSystem that inherits the oandapy.Streamer class with the following required variables in the constructor:

"""
Implementing the trend-following algorithm
for trading foreign currencies
"""
import oandapy
from datetime import datetime
import pandas as pd


class ForexSystem(oandapy.Streamer):
    def __init__(self, *args, **kwargs):
        oandapy.Streamer.__init__(self, *args, **kwargs)
        self.oanda = oandapy.API(kwargs["environment"],
                                 kwargs["access_token"])

        self.instrument = None
        self.account_id = None
        self.qty = 0
        self.resample_interval = '10s'
        self.mean_period_short = 5
        self.mean_period_long = 20
        self.buy_threshold = 1.0
        self.sell_threshold = 1.0

        self.prices = pd.DataFrame()
        self.beta = 0
        self.is_position_opened = False
        self.opening_price = 0
        self.executed_price = 0
        self.unrealized_pnl = 0
        self.realized_pnl = 0
        self.position = 0
        self.dt_format = "%Y-%m-%dT%H:%M:%S.%fZ"

We will create a method called begin in the ForexSystem class as the starting point of the program. Note that invoking self.start will begin streaming rates data:

def begin(self, **params):
    self.instrument = params["instruments"]
    self.account_id = params["accountId"]
    self.qty = params["qty"]
    self.resample_interval = params["resample_interval"]
    self.mean_period_short = params["mean_period_short"]
    self.mean_period_long = params["mean_period_long"]
    self.buy_threshold = params["buy_threshold"]
    self.sell_threshold = params["sell_threshold"]

    self.start(**params)  # Start streaming prices

Handling events

The on_success method is inherited from the oandapy.Streamer class that will handle the incoming rates data into our system. In the following code, we will parse this data into their respective variables for use in the tick_event method:

def on_success(self, data):
    time, symbol, bid, ask = self.parse_tick_data(
        data["tick"])
    self.tick_event(time, symbol, bid, ask) 

Implementing the trend-following algorithm

The tick_event method will process the tick data information by resampling the time series to calculate the beta. Note that we will store the mid-price of the bid and ask price. The beta will be used in the perform_trade_logic method to determine whether to open or close our position. The status of the system is printed on every method call:

def tick_event(self, time, symbol, bid, ask):
    midprice = (ask+bid)/2.
    self.prices.loc[time, symbol] = midprice

    resampled_prices = self.prices.resample(
        self.resample_interval,
        how='last',
        fill_method="ffill")

    mean_short = resampled_prices.tail(
        self.mean_period_short).mean()[0]
    mean_long = resampled_prices.tail(
        self.mean_period_long).mean()[0]
    self.beta = mean_short / mean_long

    self.perform_trade_logic(self.beta)
    self.calculate_unrealized_pnl(bid, ask)
    self.print_status()

In the following perform_trade_logic method, a buy signal indicates that a new long position is to be opened, or an existing short position is to be closed, by sending a buy market order. Conversely, a sell signal indicates that a new short position is to be opened, or an existing long position is to be closed, by sending a sell market order:

def perform_trade_logic(self, beta):

    if beta > self.buy_threshold:
        if not self.is_position_opened 
                or self.position < 0:
            self.check_and_send_order(True)

    elif beta < self.sell_threshold:
        if not self.is_position_opened 
                or self.position > 0:
            self.check_and_send_order(False)

The full source code for the ForexSystem class is available at the Packt Publishing website.

Tracking our positions

The print_status method displays the time, currency pair, position, beta, and profits and losses of our position during the running lifetime of the system with the following code:

def print_status(self):
    print "[%s] %s pos=%s beta=%s RPnL=%s UPnL=%s" % (
        datetime.now().time(),
        self.instrument, 
        self.position, 
        round(self.beta, 5),
        self.realized_pnl, 
        self.unrealized_pnl)

Let's start running our algorithmic trading system with the following code:

if __name__ == "__main__":
    key = "4c7718c7e03d472c2369abf1cb7ceddb-" 
          "142b7d845d68844e853bb95c63f1c8b91"
    account_id = 6858884
    system = ForexSystem(environment="practice", access_token=key)
    system.begin(accountId=account_id,
                 instruments="EUR_USD",
                 qty=1000,
                 resample_interval="10s",
                 mean_period_short=5,
                 mean_period_long=20,
                 buy_threshold=1.,
                 sell_threshold=1.) 

Here, we are specifying the system to trade 1,000 units of EUR/USD each time. The resampling period of the time series is 10-second intervals. The short-term averaging period is defined to be the recent five periods or fifty seconds. The long-term averaging period is defined to be the recent twenty periods or two hundred seconds. When the beta exceeds the buy threshold value of 1, the system will enter into a long position of 1,000 units. Otherwise, when the beta falls below the sell threshold of 1, the system will enter into a short position of 1,000 units.

The first few lines of the output should give us the following result:

[09:31:59.067633] EUR_USD pos=0 beta=1.0 RPnL=0 UPnL=0
[09:31:59.163893] EUR_USD pos=0 beta=1.0 RPnL=0 UPnL=0
[09:32:00.233068] EUR_USD pos=0 beta=1.0 RPnL=0 UPnL=0

Suppose after some time, the value of our beta decreases. Our trading system will follow the trend by placing a sell market order of 1,000 units of EUR/USD. Our output status will update with the following information:

[09:35:42.305521] EUR_USD pos=0 beta=1.0 RPnL=0 UPnL=0
Placed order sell 1000 EUR_USD at market.
[09:35:42.765773] EUR_USD pos=-1000 beta=0.99999 RPnL=0 UPnL=-0.14
[09:35:48.434842] EUR_USD pos=-1000 beta=0.99999 RPnL=0 UPnL=-0.11

[09:38:28.864373] EUR_USD pos=-1000 beta=0.99984 RPnL=0 UPnL=0.32
[09:38:29.096078] EUR_USD pos=-1000 beta=0.99984 RPnL=0 UPnL=0.31

In the fxTrade Practice platform, we should be able to view our trade:

Tracking our positions

Our trading system will run indefinitely until we terminate the process with a Ctrl + Z or something similar.

Although our trend-following trading system seems to be doing reasonable well, however, as discussed in the previous sections, more improvements are required to develop a profitable and robust trading strategy.

In the next section, we will discuss risk management for our trading systems.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.22.216.254