In [1]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
pd.options.mode.chained_assignment = None

The model in theory

We are going to use 4 features: The price itself and three extra technical indicators.

  • MACD (Trend)
  • Stochastics (Momentum)
  • Average True Range (Volume)

Functions

Exponential Moving Average: Is a type of infinite impulse response filter that applies weighting factors which decrease exponentially. The weighting for each older datum decreases exponentially, never reaching zero.

MACD: The Moving Average Convergence/Divergence oscillator (MACD) is one of the simplest and most effective momentum indicators available. The MACD turns two trend-following indicators, moving averages, into a momentum oscillator by subtracting the longer moving average from the shorter moving average.

Stochastics oscillator: The Stochastic Oscillator is a momentum indicator that shows the location of the close relative to the high-low range over a set number of periods.

Average True Range: Is an indicator to measure the volalitility (NOT price direction). The largest of:

  • Method A: Current High less the current Low
  • Method B: Current High less the previous Close (absolute value)
  • Method C: Current Low less the previous Close (absolute value)

Calculation:


In [2]:
def MACD(df,period1,period2,periodSignal):
    EMA1 = pd.DataFrame.ewm(df,span=period1).mean()
    EMA2 = pd.DataFrame.ewm(df,span=period2).mean()
    MACD = EMA1-EMA2
    
    Signal = pd.DataFrame.ewm(MACD,periodSignal).mean()
    
    Histogram = MACD-Signal
    
    return Histogram

def stochastics_oscillator(df,period):
    l, h = pd.DataFrame.rolling(df, period).min(), pd.DataFrame.rolling(df, period).max()
    k = 100 * (df - l) / (h - l)
    return k

def ATR(df,period):
    '''
    Method A: Current High less the current Low
    '''
    df['H-L'] = abs(df['High']-df['Low'])
    df['H-PC'] = abs(df['High']-df['Close'].shift(1))
    df['L-PC'] = abs(df['Low']-df['Close'].shift(1))
    TR = df[['H-L','H-PC','L-PC']].max(axis=1)
    return TR.to_frame()

Read data


In [3]:
df = pd.read_csv('EURUSD.csv',usecols=[1,2,3,4])
df = df.iloc[::-1]
df["Close"] = (df["Close"].str.split()).apply(lambda x: float(x[0].replace(',', '.')))
df["Open"] = (df["Open"].str.split()).apply(lambda x: float(x[0].replace(',', '.')))
df["High"] = (df["High"].str.split()).apply(lambda x: float(x[0].replace(',', '.')))
df["Low"] = (df["Low"].str.split()).apply(lambda x: float(x[0].replace(',', '.')))


dfPrices = pd.read_csv('EURUSD.csv',usecols=[1])
dfPrices = dfPrices.iloc[::-1]
dfPrices["Close"] = (dfPrices["Close"].str.split()).apply(lambda x: float(x[0].replace(',', '.')))

In [4]:
dfPrices.head(2)


Out[4]:
Close
2629 1.3611
2628 1.3537

Plot


In [5]:
price = dfPrices.iloc[len(dfPrices.index)-60:len(dfPrices.index)].as_matrix().ravel()

Price


In [6]:
prices = dfPrices.iloc[len(dfPrices.index)-60:len(dfPrices.index)].as_matrix().ravel()
plt.figure(figsize=(25,7))
plt.plot(prices,label='Test',color='black')
plt.title('Price')
plt.legend(loc='upper left')
plt.show()


MACD


In [7]:
macd = MACD(dfPrices.iloc[len(dfPrices.index)-60:len(dfPrices.index)],12,26,9)

In [8]:
plt.figure(figsize=(25,7))
plt.plot(macd,label='macd',color='red')
plt.title('MACD')
plt.legend(loc='upper left')
plt.show()


Stochastics Oscillator


In [9]:
stochastics = stochastics_oscillator(dfPrices.iloc[len(dfPrices.index)-60:len(dfPrices.index)],14)

In [10]:
plt.figure(figsize=(14,7))
#First 100 points because it's too dense
plt.plot(stochastics[0:100],label='Stochastics Oscillator',color='blue')
plt.title('Stochastics Oscillator')
plt.legend(loc='upper left')
plt.show()


Average True Range


In [11]:
atr = ATR(df.iloc[len(df.index)-60:len(df.index)],14)

In [12]:
plt.figure(figsize=(21,7))
#First 100 points because it's too dense
plt.plot(atr[0:100],label='ATR',color='green')
plt.title('Average True Range')
plt.legend(loc='upper left')
plt.show()


Create complete DataFrame & Save Data


In [13]:
dfPriceShift = dfPrices.shift(-1)
dfPriceShift.rename(columns={'Close':'CloseTarget'}, inplace=True)

In [14]:
dfPriceShift.head(2)


Out[14]:
CloseTarget
2629 1.3537
2628 1.3426

In [15]:
macd = MACD(dfPrices,12,26,9)
macd.rename(columns={'Close':'MACD'}, inplace=True)

In [16]:
stochastics = stochastics_oscillator(dfPrices,14)
stochastics.rename(columns={'Close':'Stochastics'}, inplace=True)

In [17]:
atr = ATR(df,14)
atr.rename(columns={0:'ATR'}, inplace=True)

In [18]:
final_data = pd.concat([dfPrices,dfPriceShift,macd,stochastics,atr], axis=1)
# Delete the entries with missing values (where the stochastics couldn't be computed yet) because have a lot of datapoints ;)
final_data = final_data.dropna()

In [19]:
final_data.info()


<class 'pandas.core.frame.DataFrame'>
Int64Index: 2616 entries, 2616 to 1
Data columns (total 5 columns):
Close          2616 non-null float64
CloseTarget    2616 non-null float64
MACD           2616 non-null float64
Stochastics    2616 non-null float64
ATR            2616 non-null float64
dtypes: float64(5)
memory usage: 122.6 KB

In [20]:
final_data


Out[20]:
Close CloseTarget MACD Stochastics ATR
2616 1.3638 1.3630 0.001322 83.268482 0.0086
2615 1.3630 1.3621 0.001137 80.155642 0.0100
2614 1.3621 1.3607 0.000913 76.653696 0.0053
2613 1.3607 1.3650 0.000640 71.206226 0.0076
2612 1.3650 1.3689 0.000659 85.844749 0.0104
2611 1.3689 1.3768 0.000856 100.000000 0.0076
2610 1.3768 1.3798 0.001402 100.000000 0.0136
2609 1.3798 1.3838 0.001888 100.000000 0.0050
2608 1.3838 1.3904 0.002376 100.000000 0.0070
2607 1.3904 1.3868 0.003010 100.000000 0.0091
2606 1.3868 1.3875 0.003100 88.000000 0.0065
2605 1.3875 1.3866 0.003071 90.333333 0.0052
2604 1.3866 1.3982 0.002859 87.205387 0.0040
2603 1.3982 1.3967 0.003314 100.000000 0.0162
2602 1.3967 1.4074 0.003384 96.000000 0.0053
2601 1.4074 1.4091 0.003967 100.000000 0.0139
2600 1.4091 1.4085 0.004305 100.000000 0.0079
2599 1.4085 1.4146 0.004306 98.639456 0.0063
2598 1.4146 1.4130 0.004508 100.000000 0.0094
2597 1.4130 1.4151 0.004331 95.767196 0.0052
2596 1.4151 1.4272 0.004136 100.000000 0.0067
2595 1.4272 1.4232 0.004602 100.000000 0.0134
2594 1.4232 1.4153 0.004429 90.147783 0.0071
2593 1.4153 1.4085 0.003542 70.689655 0.0100
2592 1.4085 1.4135 0.002251 53.940887 0.0120
2591 1.4135 1.4136 0.001520 66.256158 0.0082
2590 1.4136 1.4057 0.000869 55.409836 0.0126
2589 1.4057 1.4108 -0.000256 29.508197 0.0120
2588 1.4108 1.4147 -0.000782 23.720930 0.0100
2587 1.4147 1.4194 -0.000952 41.860465 0.0079
... ... ... ... ... ...
30 1.1752 1.1842 0.002871 100.000000 0.0094
29 1.1842 1.1801 0.003447 100.000000 0.0124
28 1.1801 1.1856 0.003354 90.744921 0.0062
27 1.1856 1.1870 0.003478 100.000000 0.0117
26 1.1870 1.1772 0.003453 100.000000 0.0063
25 1.1772 1.1795 0.002516 72.394366 0.0162
24 1.1795 1.1750 0.001831 78.873239 0.0048
23 1.1750 1.1759 0.000855 49.790795 0.0111
22 1.1759 1.1772 0.000093 51.315789 0.0076
21 1.1772 1.1820 -0.000467 57.017544 0.0082
20 1.1820 1.1780 -0.000614 77.064220 0.0099
19 1.1780 1.1735 -0.001095 53.367876 0.0072
18 1.1735 1.1770 -0.001833 30.051813 0.0106
17 1.1770 1.1724 -0.002151 25.925926 0.0098
16 1.1724 1.1762 -0.002742 0.000000 0.0128
15 1.1762 1.1816 -0.002900 26.027397 0.0068
14 1.1816 1.1762 -0.002630 63.013699 0.0099
13 1.1762 1.1807 -0.002839 26.027397 0.0081
12 1.1807 1.1799 -0.002665 86.458333 0.0084
11 1.1799 1.1926 -0.002605 78.125000 0.0037
10 1.1926 1.1979 -0.001653 100.000000 0.0169
9 1.1979 1.1972 -0.000634 100.000000 0.0068
8 1.1972 1.1883 -0.000029 97.254902 0.0124
7 1.1883 1.1910 -0.000324 62.352941 0.0105
6 1.1910 1.1859 -0.000411 72.941176 0.0091
5 1.1859 1.1896 -0.000909 52.941176 0.0131
4 1.1896 1.1914 -0.001047 67.450980 0.0070
3 1.1914 1.1917 -0.001063 74.509804 0.0073
2 1.1917 1.2023 -0.001098 71.428571 0.0048
1 1.2023 1.2035 -0.000405 100.000000 0.0147

2616 rows × 5 columns


In [21]:
final_data.to_csv('EURUSD_TechnicalIndicators.csv',index=False)