3 行 code 自動輸入帳密 Fugle API – 全自動交易 Fugle 篇

  • Post author:
  • Reading time:10 mins read

前情提要

先前的文章中,我們分兩集示範了如何使用FinLab串接永豐的API,並上傳至Google Cloud Platform (GCP),實現全自動交易。

近期收到不少同學反應,Fugle由於資安考量,不支持在設定檔中直接設定密碼,而是需要手動輸入,導致沒辦法將Fugle API打包成Cloud Function來執行全自動交易。

(以下截圖來自Fugle 官方文檔)

Fugle 自動交易限制
Fugle下單限制

考量到有許多同學使用Fugle交易,我們決定再寫一篇Fugle版本專屬的教學文章,並破解Fugle所設下的資安防線,希望對大家有所幫助!

註:本篇文章將著重解說Fugle API與永豐API在串接時的差異,並不會從頭到尾重新講解一遍。建議還沒有看過FinLab與GCP串接教學的同學,先回頭複習更詳細的教學文章(上)教學文章(下)喔!

免責聲明

FinLab於此文章中所提供的程式碼僅供參考,會隨著套件版本更動、硬體設備之故障、失效或人為上之疏失導致,導致下單狀況不如交易者之預期。使用者在使用此文章之程式碼前,務必自行審慎評估,並自負投資風險及盈虧。如使用FinLab所提供之程式碼致生損失,本公司不負擔任何賠償及法律責任。

事前準備

在開始串接Fugle的API之前,有以下幾個步驟必須先完成:

  1. 申辦Fugle券商帳戶。
  2. 參照教學文章1,申請交易API & 完成模擬測試。
  3. 參照教學文章2,送出第一筆委託單。

當你完成上述步驟,就代表你已經能順利使用Fugle的交易API囉!

溫馨提醒:記得把送出的委託單給刪除,才不會不小心成交喔!

FinLab x Fugle API

確定Fugle API運作順利後,我們將使用FinLab的內建套件來呼叫Fugle API,達到根據選股清單來進行自動交易。由於在GCP上面部署要等比較久,我們將分為兩部分測試,先確定在loacl端能順利執行後,再部署到GCP上!

開始之前,請大家先花三分鐘瀏覽有關FinLab下單串接的官方文檔,會比較快進入狀況喔!

本機端自動交易測試

策略生成

首先要有一個策略,這邊我們同樣使用官方文檔的創新高策略示範。

# 生成策略report
import finlab
finlab.login("請填入自己的FINLAB API VIP TOKEN")
from finlab.backtest import sim
from finlab import data
close = data.get("price:收盤價")
position = (close == close.rolling(250).max())
report = sim(position, resample="M",upload=False)

計算買賣張數

根據 sim() 回傳的report物件,計算每檔股票所需的買賣張數。

# 輸入投資金額、計算要投資的張數
from finlab.online.order_executor import Position

fund = 100000 #投資金額
position = Position.from_report(report, fund) #產生需要下單的股票清單 & 股數
print(position)

使用FinLab套件下委託單

使用FinLab內建的模組,直接呼叫Fugle API執行換股清單的委託單。

註:玉山富果的行情API Token可由登入富果API獲得。

# 使用FinLab串接Fugle的進行下單
from finlab.online.order_executor import OrderExecutor
from finlab.online.fugle_account import FugleAccount
import os
os.environ['FUGLE_CONFIG_PATH'] = '玉山富果交易設定檔(config.ini)路徑' 
os.environ['FUGLE_MARKET_API_KEY'] = '玉山富果的行情API Token' # 獲取市價行情以進行下單

acc = FugleAccount()
order_executer = OrderExecutor(position , account=acc)
order_executer.create_orders() # 預設使用最近一筆成交價當成限價

這時候登入Fugle的帳戶中,若有看到委託單即代表本機端的測試成功!

若要取消全部委託單,則可以執行order_executer.cancel_orders()

雲端版本測試

如同先前教學文章的做法,我們會使用GCP,把在Local端測試好的程式碼打包成函式,以Cloud Function的方式呼叫。

接下來主要會講解Fugle和永豐在串接上不同的部分,其餘絕大部分相同的步驟請同學自行參照教學文章(下)

上傳憑證

首先建立一個bucket(值區),但這時候要上傳的東西變成兩個

  1. config.ini 設定檔
  2. 交易憑證(.p12檔案)

註:為了清楚的demo,接下來的示範將預設採用以下統一命名,大家可以自行決定是否要採用一樣的命名方式。

  • bucket名稱:fugle_pass
  • 環境設定檔名:config.ini
  • 憑證檔名:fugle_cert.p12

設定檔和憑證都會在事前準備階段時取得。但在上傳前,請記得將config.ini設定檔當中的憑證路徑改成GCP上的路徑,否則GCP會抓不到你的交易憑證。

image 8
修改config.ini設定檔

環境變數設定

這邊我們要填入所需的環境變數,變數Value1~Value6需要自己填寫,Value7則複製keyrings.cryptfile.cryptfile.CryptFileKeyring 即可。

image
環境變數設定

註:打開config.ini設定檔查看其中的[User]欄位,即可找到自己的Fugle帳號。

程式碼設定

與之前的教學文相同,我們將分為以下五個檔案,其中的main.pyrun_strategy.py完全一樣,這邊就不贅述了。

12
程式碼初始設定

requirements.txt

將原先的shioaji安裝包換成fugle_trade,另外為了破解Fugle的資安防線,要再加入一個叫keyring的套件,其功用是拿來儲存帳號密碼。

# Function dependencies, for example:
# package>=version
finlab==0.3.7.dev1
fugle_trade==0.3.1
keyring==23.5.0
google-cloud-storage

bucket.py

fugle pass的bucket中,將fugle_cert.p12config.ini移到/tmp目錄底下。

from google.cloud import storage

# 將需要用到的檔案從bucket移到/tmp目錄底下
def connect_storage():
  storage_client = storage.Client()
  bucket = storage_client.bucket('fugle_pass')
  blob = bucket.blob("fugle_cert.p12")
  blob.download_to_filename('/tmp/fugle_cert.p12')  
  blob = bucket.blob("config.ini")
  blob.download_to_filename('/tmp/config.ini')  
  return

make_order.py

接下來就是最重要的問題點啦!因為Fugle強制要求在第一次使用時要親手key密碼才行,這樣就導致沒辦法在Clound Function上自動執行。

我仔細地翻閱了fugle-trade 套件的原始碼,發現Fugle在初始SDK物件時,會透過keyring這個套件,執行自定義的function去檢查是否有已存在的帳密(非第一次登入。若是第一次登入,就必須強制使用者重新輸入密碼。

同時他們還透過hashcode,對每個人的帳號進行hash之後作為keyring的backend,讓破解起來更為麻煩。

Inkedcode
fugle-trade 內部程式碼

以上算是比較細部的講解,大家有興趣也可以去翻翻看Fugle的程式碼。

看不懂也沒關係,FinLab都幫大家處理好了,只需要跟著以下步驟,加入三行程式碼即可!

首先,引入需使用的套件。

code
import 所需套件

acc = FugleAccount()前,插入以下三行程式碼。

code2 2
精華的三行程式碼!

大功告成!就這麼簡單,核心概念是在Fugle的SDK初始化之前,搶先呼叫Fugle自己的函式執行了「預登入」的動作。因此Fugle在初始化檢查的時候,就不會出現需要手動輸入密碼的問題囉!

以下附上完整的程式碼,大家可以直接拿去使用,再更動裡面的參數,就可以實現不同的資金量和下單方式囉!

import os
os.chdir("/tmp")
import keyring
import time
from fugle_trade.util import setup_keyring
from finlab.online.order_executor import Position
from finlab.online.order_executor import OrderExecutor
from finlab.online.fugle_account import FugleAccount

def make_order(report,fund=100000):
    position = Position.from_report(report, fund,odd_lot=False)
    setup_keyring(os.environ["FUGLE_ACCOUNT"])
    keyring.set_password("fugle_trade_sdk:account", os.environ["FUGLE_ACCOUNT"], os.environ["FUGLE_ACCOUNT_PASSWORD"])
    keyring.set_password("fugle_trade_sdk:cert", os.environ["FUGLE_ACCOUNT"], os.environ["FUGLE_CERT_PASSWORD"])
    acc = FugleAccount()
    order_executer = OrderExecutor(position , account=acc)
    order_executer.create_orders() # 預設使用最近一筆成交價當成限價
    # 利用預先下單,回傳下單資訊至網頁以供瀏覽 (以下可以全拿掉,留一個return即可)
    time.sleep(10) #Fugle限制兩次之間要間隔十秒
    record = order_executer.create_orders(view_only=True)
    key_list = [i for i in range(1,len(record)+1)]
    value_list = [{i['stock_id']:i['quantity']} for i in record]
    return dict(zip(key_list, value_list))

解決了關鍵問題後,其餘步驟就和永豐篇的教學文章完全相同啦,這邊就不多贅述了!

Colab 版本下單

若在雲端部署上遇到困難,歡迎到Discord詢問我們,另外我們也提供了Colab下單腳本給大家,歡迎大家依照自己的需求選擇!

小彩蛋(零股語法糖)

想必眼尖的大家已經注意到了,我們同時實作了零股下單的功能!

只要把Position.from_report(report, fund,odd_lot=False)的odd_lot變數改為True,就會變成零股下單模式囉!

這是考量到資金量較小、或策略較多的學員所設計的。目前不管永豐、Fugle目前都有零股最低手續費1元的優惠,可以最大限度地降低摩擦的手續費,讓零股盡可能貼近和整股相同的績效,希望大家會喜歡!

結論

這篇文章中,我們破解了Fugle API的限制,成功將下單函式部署在GCP上執行,讓永豐跟Fugle的FinLab用戶們都能獲得一樣的體驗。

同時我們設計了小資族友善的「零股模式」。希望從資金方面、技術方面,都能盡量降低大家實踐程式交易的門檻。

FinLab是個熱愛與使用者互動的團隊,同時會積極考慮將用戶需求納入下一步的更新規劃,也因此需要更多來自大家的feedback!如果大家喜歡這篇文章,或有任何的想法想要告訴我們,就趕快到粉絲專頁留言吧!

這次的教學就這樣告一段落了。我是阿榤,下次見,掰!(⁎⁍̴̛ᴗ⁍̴̛⁎)

阿榤

我是阿榤,不務正業的電機仔,一個願意接受幸運的人。 很高興認識大家,請多指教!