To build a financial trading algorithm in Python, it needs to be fed with data. Hence, the first step you need to master is how to collect time series data on your favorite stock. Sounds like it is difficult, right?
Luckily, someone made an awesome library pandas-datareader, which does all the hard word you for you. Let’s take a look on how easy it is.
import datetime as dt
import pandas_datareader as pdr
import matplotlib.pyplot as plt
from dateutil.relativedelta import relativedelta
# A Danish jewellery manufacturer and retailer
stock = 'PNDORA.CO'
end = dt.datetime.now()
start = end - relativedelta(years=10)
pndora = pdr.get_data_yahoo(stock, start, end)
pndora['Close'].plot()
plt.show()
Which results in a time series of the closing price as shown here.
The stock is probably quite unknown, considering it is a Danish company. But to prove a point that you can get data, including for Pandora.
In the code you see that you send a start and end date to the call fetching the data. Here we have taken the last 10 years. The object returned integrates well with the matplotlib library to make the plot.
To understand the data better, we need to explore further.
Let us explore the data object returned by the call (pndora).
To get an overview you should run the following code using the iloc-call to the Dataframe object (pndora returned by pandas_datareader).
pndora.iloc[-1]
This will show what the last item of the object looks like.
High 365.000000
Low 355.600006
Open 360.000000
Close 356.500000
Volume 446004.000000
Adj Close 356.500000
Name: 2020-06-26 00:00:00, dtype: float64
Where you have the following items.
That means, it would be natural to use Adj Close in our calculations. Hence, for each day we have the above information available.
Pandas? Yes, you read correct. But not a Panda like this the picture.
There is an awesome library Pandas in Python to make data analysis easy.
Let us explore some useful things we can do.
import datetime as dt
import pandas_datareader as pdr
import matplotlib.pyplot as plt
from dateutil.relativedelta import relativedelta
# A Danish jewellery manufacturer and retailer
stock = 'PNDORA.CO'
end = dt.datetime.now()
start = end - relativedelta(years=10)
pndora = pdr.get_data_yahoo(stock, start, end)
pndora['Short'] = pndora['Adj Close'].rolling(window=20).mean()
pndora['Long'] = pndora['Adj Close'].rolling(window=100).mean()
pndora[['Adj Close', 'Short', 'Long']].plot()
plt.show()
Which will result in the following graph.
If you inspect the code above, you see, that you easily added to two new columns (Short and Long) and computed them to be the mean value of the previous 20 and 100 days, respectively.
Further, you can add the daily percentage change for the various entries.
import datetime as dt
import pandas_datareader as pdr
import matplotlib.pyplot as plt
from dateutil.relativedelta import relativedelta
# A Danish jewellery manufacturer and retailer
stock = 'PNDORA.CO'
end = dt.datetime.now()
start = end - relativedelta(years=10)
pndora = pdr.get_data_yahoo(stock, start, end)
pndora['Short'] = pndora['Adj Close'].rolling(window=20).mean()
pndora['Long'] = pndora['Adj Close'].rolling(window=100).mean()
pndora['Pct Change'] = pndora['Adj Close'].pct_change()
pndora['Pct Short'] = pndora['Short'].pct_change()
pndora['Pct Long'] = pndora['Long'].pct_change()
pndora[['Pct Change', 'Pct Short', 'Pct Long']].loc['2020'].plot()
plt.show()
Which will result in this graph.
Again you can see how easy it is to add new columns in the Dataframe object provided by Pandas library.
For the example we will keep it simple and only focus on one stock. The strategy we will use is called the dual moving average crossover.
Simply explained, you want to buy stocks when the short mean average is higher than the long mean average value.
In the figure above, it is translates to.
To implement the simplest version of that it would be as follows.
import datetime as dt
import pandas_datareader as pdr
import matplotlib.pyplot as plt
import numpy as np
from dateutil.relativedelta import relativedelta
# A Danish jewellery manufacturer and retailer
stock = 'PNDORA.CO'
end = dt.datetime.now()
start = end - relativedelta(years=10)
pndora = pdr.get_data_yahoo(stock, start, end)
short_window = 20
long_window = 100
pndora['Short'] = pndora['Adj Close'].rolling(window=short_window).mean()
pndora['Long'] = pndora['Adj Close'].rolling(window=long_window).mean()
# Let us create some signals
pndora['signal'] = 0.0
pndora['signal'][short_window:] = np.where(pndora['Short'][short_window:] > pndora['Long'][short_window:], 1.0, 0.0)
pndora['positions'] = pndora['signal'].diff()
To visually see where to buy and sell you can use the following code afterwards on pndora.
fig = plt.figure()
ax1 = fig.add_subplot(111, ylabel='Price')
pndora[['Adj Close', 'Short', 'Long']].plot(ax=ax1)
ax1.plot(pndora.loc[pndora.positions == 1.0].index,
pndora.Short[pndora.positions == 1.0],
'^', markersize=10, color='m')
ax1.plot(pndora.loc[pndora.positions == -1.0].index,
pndora.Short[pndora.positions == -1.0],
'v', markersize=10, color='k')
plt.show()
Which would result in the following graph.
Finally, you need to see how your algorithm performs.
There are many ways to test an algorithm. Here we go all in each cycle. We buy as much as we can and sell them all when we sell.
import datetime as dt
import pandas_datareader as pdr
import matplotlib.pyplot as plt
import numpy as np
from dateutil.relativedelta import relativedelta
# A Danish jewellery manufacturer and retailer
stock = 'PNDORA.CO'
end = dt.datetime.now()
start = end - relativedelta(years=10)
pndora = pdr.get_data_yahoo(stock, start, end)
short_window = 20
long_window = 100
pndora['Short'] = pndora['Adj Close'].rolling(window=short_window).mean()
pndora['Long'] = pndora['Adj Close'].rolling(window=long_window).mean()
# Let us create some signals
pndora['signal'] = 0.0
pndora['signal'][short_window:] = np.where(pndora['Short'][short_window:] > pndora['Long'][short_window:], 1.0, 0.0)
pndora['positions'] = pndora['signal'].diff()
cash = 1000000
stocks = 0
for index, row in pndora.iterrows():
if row['positions'] == 1.0:
stocks = int(cash//row['Adj Close'])
cash -= stocks*row['Adj Close']
elif row['positions'] == -1.0:
cash += stocks*row['Adj Close']
stocks = 0
print("Total:", cash + stocks*pndora.iloc[-1]['Adj Close'])
Which results in.
Total: 2034433.8826065063
That is a double in 10 years, which is less than 8% per year. Not so good.
As this is one specific stock, it is not fair to judge the algorithm being poor, it can be the stock which was not performing good, or the variables can be further adjusted.
If compared with the scenario where you bought the stocks at day one and sold them on the last day, your earnings would be 1,876,232. Hence, the algorithm beats that.
This is a simple financial trading algorithm in Python and there are variables that can be adjusted. The algorithm was performing better than the naive strategy to buy on day one and sell on the last day.
It could be interesting to add more data into the decision in the algorithm, which might be some future work to do. Also, can it be combined with some Machine Learning?
Build and Deploy an AI App with Python Flask, OpenAI API, and Google Cloud: In…
Python REST APIs with gcloud Serverless In the fast-paced world of application development, building robust…
App Development with Python using Docker Are you an aspiring app developer looking to level…
Why Value-driven Data Science is the Key to Your Success In the world of data…
Harnessing the Power of Project-Based Learning and Python for Machine Learning Mastery In today's data-driven…
Is Python the right choice for Machine Learning? Should you learn Python for Machine Learning?…