【程式交易實戰】從零開始建置股票當沖策略(內含策略 sample code)
歡迎來到 程式交易實戰 ,若還不了解程式交易可以 參考 此文章 ! 我們現在就來談談交易策略架構以及如何實作當沖策略吧!
讀完本篇文,您將學會...
- 熟悉交易策略的組成 - 指標、訊號、方法
- 開發出簡單的當沖策略:開盤買 / 收盤賣
- 開發出進階的當沖策略:ORB 策略
交易策略的組成 - 指標、訊號、方法
一個完整的量化交易策略是由「指標」、「訊號」、「方法」所組成,假設我們想要在「股價向上突破 5 日均線時買進」,那指標就是「 5 日均線」,訊號是「向上突破」,方法則是「買進」等買賣操作。如下圖所示:
策略通常是為了達成目標而制定的,再舉個更生活化的例子,若今天想要在門票開賣時搶購演唱會門票;目標是「買到演唱會門票」,所以為了達成這個目的,我們需要制定一個策略來達成,而這個策略按照上面的例子可能會是「一刻不差的在開賣第一時刻要按下購票 CTA 按鈕」。
所以假設張惠妹演唱會在 2022 年 9 月 1 日 00:00 在 KKTIX 開賣,那指摽是「開賣時間:2022 年 9 月 1 日 00:00 」,訊號是「到達開賣時間」,方法就是「按下購票按鈕」。看似很簡單的事件流程,但在量化交易的世界裡,這些都是可以做修改、驗證及分析的,在往後的課 程裡我們會更具體的介紹策略開發的流程以及分析方法。
如何實作
廢話不多說,直接進入實作的部分吧!首先會需要先準備環境,若您尚未申請元富交易 API,可參考 事前準備。
若已完成申請,可直接執行以下 code 進行登入
from masterlink_sdk import MasterlinkSDK, Order, BSAction, TimeInForce, OrderType, PriceType, MarketType
# 登入
sdk = MasterlinkSDK()
accounts = sdk.login("Your ID", "Your Password", "Your Cert Path", "Your Cert Password")
開發簡單的當沖策略 - 開盤買/收盤賣
當登入完成後,就可以進行當沖策略開發的部分囉!
我們以曾經紅極一時的長榮(2603.tw)這檔股票作為範例,但在開發當沖策略前,您也需要留意自身有無當沖權限,另外也需查詢該檔股票是否可以當沖哦!我們可以透過 MarginQuota
來確認該股票是否有當沖權限的狀態,程式碼如下:
# 取得行情權限
sdk.init_realtime(accounts[0])
# 使用行情 API
restStock = sdk.marketdata.rest_client.stock
# 確認您是否有當沖權限
user_dayTrade_status = accounts[0].s_mark
symbol = "2603"
# 須先確認該股票是否可以先買後賣
symbol_canDayBuySell = restStock.intraday.ticker(symbol=symbol)['canBuyDayTrade']
確認有當沖權限及股票狀態可行後,我們直接實作一個簡單的策略:開盤買進、收盤賣出!
為了盡可能達成目的,我們需要...
- 開盤時買進,要在 09:00:00 以市價買進。
- 收盤時賣出,要在 13:25:00 以跌停價賣出。
# 使用相關套件
import datetime
import time
# 用來記錄部位狀態
position = 0
# 確認是否有當沖權限:Y -> 已開啟先買後賣的當沖權限、B -> 已開啟先買後賣、先賣後買的當沖權限
if user_dayTrade_status not in ['Y','B']:
raise Exception("您目前無法進行先買後賣的當沖操作!")
# 須確認該檔股票是否可以當沖
if symbol_canDayBuySell == False:
raise Exception("您選擇的股票無法進行先買後賣操作,請換檔股票試試!")
# 首先我們必須要隨時檢查目前的時間是否是這兩個時間點
while True:
# 時間是9點
if datetime.time(9, 1) >= datetime.datetime.now().time() > datetime.time(9, 0) and position == 0:
order = Order(
buy_sell= BSAction.Buy,
price_type=PriceType.Market, # 市價買進
price='',
symbol=symbol,
quantity=1000,
market_type=MarketType.Common,
order_type=OrderType.Stock,
)
sdk.stock.place_order(accounts[0],order)
# 已經買進,避免重複下單
position = position + 1 # position 為 0 指沒有部位、position 為 1 指有部位
# 已經到收盤時間 且 有部位
if datetime.time(13, 26) >= datetime.datetime.now().time() >= datetime.time(13, 25) and position != 0:
order = OrderObject(
buy_sell= BSAction.Sell,
price_type=PriceType.LimitDown, # 跌停賣出
price='',
symbol=symbol,
quantity=1000,
market_type=MarketType.Common,
order_type=OrderType.DayTradingSell, # 為現股當沖賣出,因此以交易類別來說需要設定為現股當沖賣(DayTradingSell)
)
sdk.stock.place_order(order)
# 已經賣出,部位歸零
position = 0
break
請注意!! 若您使用 Colab 進行實作,因 Colab server 的時間與本機端時間可能不一致,因此您須自行調整開收盤時間!