用python炒股?python除了生孩子還有什麼不能的!

不用深厚的數學功底也不用深厚的金融知識, 本文中也不會引用各種高深的投資模型或數學模型。這不用,那不用的,到底怎麼用python炒股?往下看

交易系統

在交易之前,我們應該首先有一個交易系統用於指導我們自己交易,不一定有什麼規範,但是可以作爲一個交易的依據,至於這個依據可不可行,科不科學那就見仁見智了。

當然了,這裏的交易系統不一定是程序,只是指你自己的交易原則或者遵守的一些技巧或者方法,你可以手動執行也可以藉助編程語言,編程語言不就是一套用來使用的工具麼.

這裏參考海龜交易法則裏面的交易體系(這裏只是參考大方向). 建立一個完善的交易體系,我們至少應該思考一下六個方面。

1、市場----買賣什麼 2、頭寸規模----買賣多少 3、入市----何時買入 4、止損----何時退出虧損的頭寸 5、止盈----何時退出盈利的頭寸 6、離市----何時離市

簡單的示例

買賣A股 全倉 當日漲幅超過3%買入。 當持有頭寸虧損超過3%,平倉 當日跌幅大於3%或者三個連續陰線

分析: 這個交易策略其實只有在行情以波浪形狀向上的行情時候才能獲利,如果是盤整的情況下,怕是會虧的很慘。這裏之所以寫的這麼簡單粗暴是爲了後面策略測試擼代碼簡單。

數據獲取及處理

因爲這裏說的是用python炒股,所以應該採用程序的方式去獲取數據,如果人工炒股,下載任何股票行情軟件都是可以的,但是人工的執行是需要花費比較多的精力的。

而python語言中用於獲取股票行情數據的庫,最有名莫過於tushare了。

這裏以上證樂視的股票爲例吧。

python環境安裝

Python資料分享羣【 784758214 】羣內有安裝包和學習視頻資料,零基礎,進階,領取永久的實戰免費在線直播課程,大牛在線解答疑問。希望可以幫助你快速瞭解Python、學習python

獲取行情數據

import pandas as pd
import tushare as ts

通過股票代碼獲取股票數據,這裏沒有指定開始及結束日期

df = ts.get_k_data("300104")

查看前十條數據

df.head()

查看後十條數據

df.tail()

將數據的index轉換成date字段對應的日期

df.index = pd.to_datetime(df.date)

將多餘的date字段刪除

df.drop("date", inplace=True, axis=1)

計算常用指標

# 計算5,15,50日的移動平均線, MA5, MA15, MA50
days = [5, 15, 50]
for ma in days:
    column_name = "MA{}".format(ma)
    df[column_name] = pd.rolling_mean(df.close, ma)

# 計算浮動比例
df["pchange"] = df.close.pct_change()
# 計算浮動點數
df["change"] = df.close.diff()

最終處理完成後的結果如下:

df.head()
Out[13]: 
             open  close   high    low    volume    code     MA5  MA15  MA50  \
date                                                                           
2013-11-29  9.396  9.741  9.870  9.389  146587.0  300104     NaN   NaN   NaN   
2013-12-02  9.298  8.768  9.344  8.768  177127.0  300104     NaN   NaN   NaN   
2013-12-03  8.142  8.414  8.546  7.890  176305.0  300104     NaN   NaN   NaN   
2013-12-04  8.391  8.072  8.607  8.053  120115.0  300104     NaN   NaN   NaN   
2013-12-05  7.983  7.366  8.108  7.280  253764.0  300104  8.4722   NaN   NaN   

             pchange  change  
date                          
2013-11-29       NaN     NaN  
2013-12-02 -0.099887  -0.973  
2013-12-03 -0.040374  -0.354  
2013-12-04 -0.040647  -0.342 

可視化

走勢圖

所謂一圖勝前言,將數據可視化可以非常直觀的感受到股票的走勢。 個人覺得,如果用程序炒股還是應該一切都量化的,不應該有過多的主觀觀點,如果過於依賴直覺或者當時心情,那麼實在沒必要用程序分析了。

df[["close", "MA5", "MA15", "MA50"]].plot(figsiz=(10,18))

效果如下:

k線圖

import matplotplib.pyplot as plt
from matplotlib.daet import DateFormatter
from matplotlib.finance import date2num, candlestick_ohlc

def candlePlot(data, title=""):
    data["date"] = [date2num(pd.to_datetime(x)) for x in data.index]
    dataList = [tuple(x) for x in data[
        ["date", "open", "high", "low", "close"]].values]

    ax = plt.subplot()
    ax.set_title(title)
    ax.xaxis.set_major_formatter(DateFormatter("%y-%m-%d"))
    candlestick_ohlc(ax, dataList, width=0.7, colorup="r", colordown="g")
    plt.setp(plt.gca().get_xticklabels(), rotation=50,
             horizontalalignment="center")
    fig = plt.gcf()
    fig.set_size_inches(20, 15)
    plt.grid(True)

candlePlot(df)

效果如下:

策略測試

手動擼代碼 京東方A(000725)。

# 導入相關模塊
import tushare as ts
import pandas as pd

# 獲取數據
df = ts.get_k_data("000725")

# 處理數據
df.index = pd.to_datetime(df.date)
df.drop("date", axis=1, inplace=True)

# 計算浮動比例
df["pchange"] = df.close.pct_change()
# 計算浮動點數
df["change"] = df.close.diff()

# 查看當前數據數據前五行
             open  close   high    low      volume    code   pchange  change
date                                                                        
2015-07-20  4.264  4.234  4.342  4.165  13036186.0  000725       NaN     NaN
2015-07-21  4.136  4.195  4.274  4.096   8776773.0  000725 -0.009211  -0.039
2015-07-22  4.175  4.146  4.214  4.067   9083703.0  000725 -0.011681  -0.049
2015-07-23  4.136  4.254  4.283  4.096  12792734.0  000725  0.026049   0.108
2015-07-24  4.224  4.136  4.254  4.106  13009620.0  000725 -0.027739  -0.118

# 設定回撤值
withdraw = 0.03
# 設定突破值
breakthrough = 0.03
# 設定賬戶資金
account = 10000
# 持有倉位手數
position = 0

def buy(bar):
    global account, position
    print("{}: buy {}".format(bar.date, bar.close))
    # 一手價格
    one = bar.close * 100
    position = account // one
    account = account - (position * one)

def sell(bar):
    global account, position
    # 一手價格
    print("{}: sell {}".format(bar.date, bar.close))
    one = bar.close * 100
    account += position * one
    position = 0

print("開始時間投資時間: ", df.iloc[0].date)
for date in df.index:
    bar = df.loc[date]
    if bar.pchange and bar.pchange > breakthrough and position == 0:
        buy(bar)
    elif bar.pchange and bar.pchange < withdraw and position > 0:
        sell(bar)

print("最終可有現金: ", account)
print("最終持有市值: ", position * df.iloc[-1].close * 100)

輸出如下:

開始時間投資時間: 2015-07-20 2015-07-29: buy 3.83 2015-07-30: sell 3.653 2015-08-04: buy 3.752 ...... 2018-02-27: sell 5.71 2018-03-06: buy 5.79 最終可有現金: 333.3 最終持有市值: 7527.0

結論: 通過上面的測試發現資虧了兩千多...

藉助測試框架 藉助測試框架纔是正確的回撤姿勢,因爲框架包含了更多的功能。這裏使用pyalgotrade。

簡單使用

from pyalgotrade import strategy
from pyalgotrade import technical
from pyalgotrade.barfeed import yahoofeed

# 自定義事件窗口類
class DiffEventWindow(technical.EventWindow):
    def __init__(self, period):
        assert(period > 0)
        super(DiffEventWindow, self).__init__(period)
        self.__value = None

    def onNewValue(self, dateTime, value):
        super(DiffEventWindow, self).onNewValue(dateTime, value)
        if self.windowFull():
            lastValue = self.getValues()[0]
            nowValue = self.getValues()[1]
            self.__value = (nowValue - lastValue) / lastValue

    def getValue(self):
        return self.__value

# 自定義指標
``
class Diff(technical.EventBasedFilter):
    def __init__(self, dataSeries, period, maxLen=None):
        super(Diff, self).__init__(dataSeries, DiffEventWindow(period), maxLen)

# 定義自己的策略

class MyStrategy(strategy.BacktestingStrategy):
    def __init__(self, feed, instrument, diffPeriod=2):
        # 傳入feed及初始賬戶資金
        super(MyStrategy, self).__init__(feed, 10000)
        self.__instrument = instrument
        self.__position = None
        self.setUseAdjustedValues(True)
        self.__prices = feed[instrument].getPriceDataSeries()
        self.__diff = Diff(self.__prices, diffPeriod)
        self.__break = 0.03
        self.__withdown = -0.03

    def getDiff(self):
        return self.__diff

    def onEnterCanceled(self, position):
        self.__position = None

    def onEnterOk(self, position):
        execInfo = position.getEntryOrder().getExecutionInfo()
        self.info("BUY at $%.2f" % (execInfo.getPrice()))

    def onExitOk(self, position):
        execInfo = position.getExitOrder().getExecutionInfo()
        self.info("SELL at $%.2f" % (execInfo.getPrice()))
        self.__position = None

    def onExitCanceled(self, position):
        # If the exit was canceled, re-submit it.
        self.__position.exitMarket()

    def onBars(self, bars):
        account = self.getBroker().getCash()
        bar = bars[self.__instrument]
        if self.__position is None:
            one = bar.getPrice() * 100
            oneUnit = account // one
            if oneUnit > 0 and self.__diff[-1] > self.__break:
                self.__position = self.enterLong(self.__instrument, oneUnit * 100, True)
        elif self.__diff[-1] < self.__withdown and not self.__position.exitActive():
            self.__position.exitMarket()

def runStrategy():

    # 下載數據


    jdf = ts.get_k_data("000725")

    # 新建Adj Close字段
    jdf["Adj Close"] =jdf.close

    # 將tushare下的數據的字段保存爲pyalgotrade所要求的數據格式
    jdf.columns = ["Date", "Open", "Close", "High", "Low", "Volume", "code", "Adj Close"]

    # 將數據保存成本地csv文件
    jdf.to_csv("jdf.csv", index=False)

    feed = yahoofeed.Feed()
    feed.addBarsFromCSV("jdf", "jdf.csv")

    myStrategy = MyStrategy(feed, "jdf")

    myStrategy.run()
    print("Final portfolio value: $%.2f" % myStrategy.getResult())

    runStrategy()

輸出如下

2015-07-30 00:00:00 strategy [INFO] BUY at

3.57 2015-08-05 00:00:00 strategy [INFO] BUY at

3.56 ... 2018-02-13 00:00:00 strategy [INFO] BUY at

7877.30 猛地一看會發現,用框架似乎寫了更多的代碼,但是框架內置了更多分析工具。 下面簡單介紹。

策略可視化

from pyalgotrade import strategy
from pyalgotrade import technical
from pyalgotrade.barfeed import yahoofeed
from pyalgotrade import plotter
from pyalgotrade.stratanalyzer import returns

class DiffEventWindow(technical.EventWindow):
    def __init__(self, period):
        assert(period > 0)
        super(DiffEventWindow, self).__init__(period)
        self.__value = None

    def onNewValue(self, dateTime, value):
        super(DiffEventWindow, self).onNewValue(dateTime, value)
        if self.windowFull():
            lastValue = self.getValues()[0]
            nowValue = self.getValues()[1]
            self.__value = (nowValue - lastValue) / lastValue

    def getValue(self):
        return self.__value

class Diff(technical.EventBasedFilter):
    def __init__(self, dataSeries, period, maxLen=None):
        super(Diff, self).__init__(dataSeries, DiffEventWindow(period), maxLen)

class MyStrategy(strategy.BacktestingStrategy):
    def __init__(self, feed, instrument, diffPeriod=2):
        super(MyStrategy, self).__init__(feed, 10000)
        self.__instrument = instrument
        self.__position = None
        self.setUseAdjustedValues(True)
        self.__prices = feed[instrument].getPriceDataSeries()
        self.__diff = Diff(self.__prices, diffPeriod)
        self.__break = 0.03
        self.__withdown = -0.03

    def getDiff(self):
        return self.__diff

    def onEnterCanceled(self, position):
        self.__position = None

    def onEnterOk(self, position):
        execInfo = position.getEntryOrder().getExecutionInfo()
        self.info("BUY at $%.2f" % (execInfo.getPrice()))

    def onExitOk(self, position):
        execInfo = position.getExitOrder().getExecutionInfo()
        self.info("SELL at $%.2f" % (execInfo.getPrice()))
        self.__position = None

    def onExitCanceled(self, position):
        # If the exit was canceled, re-submit it.
        self.__position.exitMarket()

    def onBars(self, bars):
        account = self.getBroker().getCash()
        bar = bars[self.__instrument]
        if self.__position is None:
            one = bar.getPrice() * 100
            oneUnit = account // one
            if oneUnit > 0 and self.__diff[-1] > self.__break:
                self.__position = self.enterLong(self.__instrument, oneUnit * 100, True)
        elif self.__diff[-1] < self.__withdown and not self.__position.exitActive():
            self.__position.exitMarket()

def runStrategy():
    # 下載數據
    jdf = ts.get_k_data("000725")

    # 新建Adj Close字段
    jdf["Adj Close"] =jdf.close

    # 將tushare下的數據的字段保存爲pyalgotrade所要求的數據格式
    jdf.columns = ["Date", "Open", "Close", "High", "Low", "Volume", "code", "Adj Close"]

    # 將數據保存成本地csv文件
    jdf.to_csv("jdf.csv", index=False)

    feed = yahoofeed.Feed()
    feed.addBarsFromCSV("jdf", "jdf.csv")

    myStrategy = MyStrategy(feed, "jdf")

    returnsAnalyzer = returns.Returns()
    myStrategy.attachAnalyzer(returnsAnalyzer)
    plt = plotter.StrategyPlotter(myStrategy)
    plt.getInstrumentSubplot("jdf")
    plt.getOrCreateSubplot("returns").addDataSeries("Simple returns", returnsAnalyzer.getReturns())

    myStrategy.run()
    print("Final portfolio value: $%.2f" % myStrategy.getResult())
    plt.plot()

runStrategy()

圖片輸出如下

股價監控

根據這個需求寫了一個股價監控的半成品,通過郵箱監控。 項目參考: https://github.com/youerning/UserPyScript/tree/master/monitor

技巧:在微信的輔助功能裏面啓用QQ郵箱提醒的功能,那麼股價變動的通知就會很及時了,因爲微信幾乎等同於短信了。

這裏簡單說一下各個配置項及使用方法。

default段落

breakthrough代表突破的比例,需要傳入兩個值,項目裏面的突破比例依次是3%,5%.

withdraw代表回撤,也需要兩個值,示例爲3%,5%.

attention代表關注的股票列表,填入關注的股票代碼,用空格隔開 注:這裏暫時沒有考慮關注股票的情況,所以很多的關注股票也許有性能上的問題。

mail段落

依次輸入用戶名及密碼以及收件人的郵箱

position段落

當前持倉的股票以及其持倉成本。 如持有京東方A(000725)以5.76的股價。 000725 = 5.76 如果多個持倉就多個如上的相應的鍵值對。

使用方法參考該腳本的readme https://github.com/youerning/UserPyScript/blob/master/monitor/README.md

==PS:很難過的是英文水平不好還用因爲註釋,以及用英文詞彙做變量名,如果詞不達意請見諒。==

下單

這一部分本人暫時沒有讓程序自動執行,因爲暫時還沒有打磨出來一套適合自己並相信的體系,所以依靠股價監控的通知,根據不斷修正的體系在手動執行交易。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章