پیاده سازی یک استراتژی معاملات الگوریتمی بر روی سهم فولاد با پایتون

سلام دوستان تو این مطلب میخوایم یک استراتژی معاملات الگوریتمی ساده رو برای سهم فولاد مبارکه اصفهان، با پایتون پیاده سازی کنیم.با انجام این کار چیزهای جنبی خوبی یاد میگیریم (از نحوه وارد کردن دیتای سهام بورس ایران به پایتون گرفته تا پیش پردازش و استاندارد کردن و....)

استراتژی:استراتژی ما ساده است!
قیمت بسته شدن (close) سهم فولاد رو به همراه دو تا میانگین متحرکش در نظر می گیریم.(یکی کوتاه مدت و یکی بلند مدت) میگیم :
* هر وقت میانگین متحرک کوتاه مدت، بلند مدت رو قطع کرد و ازش بیشتر شد؛ تو سیگنال خرید بده.
* هر وقت میانگین متحرک کوتاه مدت، بلند مدت رو قطع کرد و ازش کمتر شد؛ تو سیگنال فروش بده

خب اولین کاری که باید انجام بدیم اینه که دیتای مربوط به سهم فولاد مبارکه اصفهان رو از سایت شركت مديريت فناوری بورس تهران دریافت کنیم.پس به این سایت میریم و وارد صفحه مربوط به سهم فولاد میشیم.بالا سمت چپ یک گزینه به اسم "تهیه خروجی" هستش.مطابق عکس زیر روی اون قسمت کلیک می‌کنیم تا تاریخچه سهم فولاد رو از اولین روز تا آخرین روز معاملاتیش در قالب یک فایل csv به اسم S_Mobarakeh.Steel داشته باشیم.

برای هر سهمی که بخواید می‌تونید از همین روش تاریخچه معاملاتیش رو بدست بیارید.
برای هر سهمی که بخواید می‌تونید از همین روش تاریخچه معاملاتیش رو بدست بیارید.

خب حالا ژوپیتر نوت‌بوک رو باز می‌کنیم تا کد زدنمون رو شروع کنیم :)

برای اینکه موقع ایمپورت کردن اون فایل csv تو پایتون درگیر تایپ آدرس نشید اول این کد رو ران کنید:

import os
os.getcwd()

خروجی این کد یه آدرس تو کامپیوتر شماست، هر آدرسی که بهتون داد، اون فایل csv رو ببرید همونجا قرارش بدید.

ما برای انجام این پروژه به 3 تا کتابخونه نیاز داریم، پس اول اونارو ایمپورت می کنیم:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

خب حالا با استفاده از کتابخونه پانداس که با مخفف pd صداش میکنیم میایم اون فایل csv رو ایمپورت میکنیم:

data_folad=pd.read_csv('S_Mobarakeh.Steel.csv')
data_folad

با اون کاری که همون اول کردیم (یعنی قرار دادن فایل csv تو مسیر دایرکتوری) دیگه اینجا راحت بودیم.

ما اطلاعات 2984 روز معاملاتی این سهم رو در اختیار داریم.با توجه به استراتژیمون، فقط ستون close برامون مهمه.
ما اطلاعات 2984 روز معاملاتی این سهم رو در اختیار داریم.با توجه به استراتژیمون، فقط ستون close برامون مهمه.

ما برای انجام کارمون به ستون هایی غیر از ستون close نیازی نداریم.

پس یه دیتا فریم به اسم df میسازیم که اندیسش ستون <DTYYYYMMDD> یا همون تاریخ دیتا فریم data_folad باشه ( تو خط اول کد زیر این کارو انجام دادیم)

df=pd.DataFrame(index=data_folad['<DTYYYYMMDD>'])
df.index.name="date"
df.index=pd.to_datetime(df.index,format='%Y%m%d')
df['close']=pd.array(data_folad['<CLOSE>'])
df

تو خط دوم چون اسم <DTYYYYMMDD> واسه اندیس یکم غلط اندازه اون رو به "date" تغییر میدیم.

خط سوم مهمه!دیتایی که سایت به ما میده تو ستون تاریخ، اعداد فرمت تاریخ ندارند به همین خاطر اگر اونارو به فرمت تاریخ تبدیل نکنیم موقع نمودار کشیدن اذیت میشیم.

خب تا اینجا ما فقط یه دیتا فریم خالی به اسم df ساختیم که فقط اندیس داره.تو خط چهارم یه ستون به close واسه این دیتا فریم ایجاد میکنیم که این ستون همون ستون close دیتا فریم data_folad هستش.(چون اندیس این دوتا فریم متفاوته مجبور بودیم ستون close رو به array تبدیل کنیم).

df=df.sort_index()
df

با ران کردن قسمت بالا هدفمون اینه که دیتا فریممون رو بر حسب تاریخ مرتب کنیم.

خب تا اینجا تقریبا کارهای پیش پردازش تموم میشه.نمودار قیمت close رو رسم میکنیم تا یه شهودی نسبت بهش پیدا کنیم:

fig = plt.figure(figsize=(15,5))
ax1 = fig.add_subplot(111, ylabel=' price in Rials')
df['close'].plot(ax=ax1,color='b', lw=1.5)
plt.title("folad stock from 2007 to 2020")
plt.show()
قیمت سهم فولاد از 2007 تا امروز
قیمت سهم فولاد از 2007 تا امروز

تو قسمت بعدی یه تابع مینویسم که دیتا فریممون رو از ما بگیره و دوره های میانگین متحرک های کوتاه و بلند رو ازمون بپرسه و خروجی بهمون یه دیتا فریم بده، دیتافریمی که شامل مقادیر میانگین متحرک ها تو هر روز و از اون مهمتر سیگنال خرید و فروشه(orders)

def double_moving_average(financial_data,short_window,long_window):
    signals = pd.DataFrame(index=financial_data.index)
    signals['signal'] = 0.0
    signals['short_mavg'] = financial_data['close'].\
    rolling(window=short_window,min_periods=1, center=False).mean()
    signals['long_mavg'] = financial_data['close'].\
    rolling(window=long_window,min_periods=1, center=False).mean()
    signals['signal'][short_window:] =\
    np.where(signals['short_mavg'][short_window:]>signals['long_mavg'][short_window:], 1.0, 0.0)
    signals['orders'] = signals['signal'].diff()
    return signals


دو تا نکته:
1.بک اسلش یا همون \ تو کد چیز ترسناکی نیست،بک اسلش اجازه میده کدتون منظم باشه یعنی میتونی ادامه کد رو تو خط بعدی بنویسی بدون اینکه به مشکل بربخوری چون اگر بک اسلش نذاری پایتون به فضاهای خالی ارور میده.
2.با توابع جالب رولینگ ویندوز میتونید اینجا آشنا بشید.

خب حالا وقتشه از تابعی که نوشتیم کار بکشیم. دیتا فریم df رو میدیم بهش و دوره هارو 20 و 100 روزه در نظر می گیریم:

ts=double_moving_average(df,20,100)
ts

خب حالا با توجه به ستون orders دیتا فریم ts شروع میکنیم از سال 2007 تا الان روی سهم فولاد خرید و فروش زدن.

نتیجه رو با کد زیر مصورسازی می کنیم :

fig = plt.figure(figsize=(20,10))
ax1 = fig.add_subplot(111, ylabel='price in Rials')
df["close"].plot(ax=ax1,color='b', lw=2)
ts["short_mavg"].plot(ax=ax1, color='r', lw=1.5)
ts["long_mavg"].plot(ax=ax1, color='y', lw=1.5)
ax1.plot(ts.loc[ts.orders== 1.0].index,df["close"][ts.orders == 1.0],'^', markersize=6, color='c')
ax1.plot(ts.loc[ts.orders== -1.0].index,df["close"][ts.orders == -1.0],'v', markersize=6, color='k')
plt.legend(["Price","Short mavg","Long mavg","Buy","Sell"])
plt.title("Double Moving Average Trading Strategy for folad stock")
plt.show()

و اما نتیجه نهایی :

خب اینجا پایان کار نیست! اینجا تازه شروع کاره
خب اینجا پایان کار نیست! اینجا تازه شروع کاره

همونطور که میبینید این استراتژی الگوریتمی پیشنهاد های خریدش خوب بوده یعنی تقریبا قبل از هر صعود شارپی یه پیشنهاد خرید داشته اما تو پیشنهاد فروشاش به نظر زیاد موفق نبوده!(با توجه به سطح سادگیش،انتظار بیشتر هم نداریم)

هدف این بود که پیاده سازی یه همچین پروژه ی ساده ای رو ببینیم تا دستمون راه بیفته یکم.

اگر خیلی بخوایم کاربردی وارد این موضوع بشیم باید رو استراتژی های کامل تری کار کنیم.



با احترام


مسعود قهرمانی (آبان 99)


کانال تلگرام من