前言
好久沒更新了啊~~
絕對不是因為最近行情好才又回來寫這個系統,只是在今年(2025 年)4 月初時,因為每天人工確認有無逆價差且又找不到讓人太洩氣,所以就怒轉倉到半年後(逆價差有 250 多點),所以沒有轉倉需求的我就沒在繼續開發了,但該來的還是得來,就把程式寫完吧!
進行期貨程式交易之前
一樣參考他們的文件 服務條款簽署 – Shioaji 去進行 API 下單測試,雖然文件沒寫要簽什麼,但就我的印象好像只要簽 API 期貨下單簽署 就好了,

然後 follow 文件的說明完成測試就好囉,測試完後會在 API 期貨下單簽署 頁下方看到相關資訊。

實做轉倉策略啦!
下一步就是要來繼續實作下圖紅框的部份啦!也就是取得歷史價格、執行轉單策略以及最後的下單。

程式架構
加入紅框後的程式架構長這樣,以下挑一些比較重要的程式來說明。

core/strategy.py – 策略細節
這裡就是存放所有策略的程式,目前共有 3 個策略:
- LowerThanMinOfXDaysStrategy 當累積超過 10 天的期貨資料後,判斷當下的價差是否低於歷史價差最小值。
- LowerThanMedianOfXDaysStrategy 當累積超過 10 天的期貨資料後,判斷當下的價差是否低於歷史價差中位數。
- MustBuyIfSettlementThisWeekStrategy 若當週是近月期貨合約結算週,就 return True,就給它轉倉下去。
lambda_function/future_rollover.py – lambda 程式進入點
future_rollover.py 就是我們的程式進入點,除了取得當下的期貨價格外,也用以下程式來判斷是否要執行轉倉,
if is_hold_future(api, next_two_month_future_contract): # 是否持有次月期貨
print("holding the next two month future contract, end the lambda")
return
check_days = os.getenv("check_days", 10)
strategies = [MustBuyIfSettlementThisWeekStrategy(), LowerThanMedianOfXDaysStrategy(dynamodb_client, check_days)] # 預計要執行的策略們
is_buy = is_buy_by_strategies(strategies, recently_future_contract, next_two_month_future_contract) # 執行策略邏輯判斷是否要轉倉
print(f"do i rollover future? -> {is_buy}")
if is_buy:
if is_hold_future(api, recently_future_contract): # 檢查是否已經持有次月期貨
trade(api, Action.Sell, recently_future_contract) # 賣掉近月期貨
trade(api, Action.Buy, next_two_month_future_contract) # 買入次月期貨
else:
print("not holding the recent future contract, end the trade")
function is_buy_by_strategies 判斷的方式是只要任一策略回傳 True,就直接回傳 True,
另外要留意的是這裡的邏輯都是來判斷全有或全沒有,意思是在我的情況下,並不會 同時 持有近月和次月期貨合約,要嘛就是全部都持有近月期貨合約,執行轉倉後就全部持有次月期貨合約。
future/trading.py – 交易程式
主要進行交易的程式,首先會判斷目前是否有委托中的期貨合約,若有,就依照目前的期貨價格改價,若無,就進行對應的交易。
def trade(api, action: Action, contract: Future):
api.update_status(api.futopt_account)
all_trades = api.list_trades()
today = datetime.now().strftime('%Y-%m-%d')
trades = [trade for trade in all_trades if
(trade.status.status == Status.Submitted or trade.status.status == Status.PreSubmitted)
and trade.status.order_datetime.strftime('%Y-%m-%d') == today
and trade.contract.code == contract.code and trade.order.action == action]
if trades:
print(f"found [{len(trades)}] submitted trades need to be update price")
for trade in trades:
new_price = contract.reference
api.update_order(
trade,
price=new_price
)
original_price = trade.status.modified_price or trade.order.price
print(f"original price: {original_price}, updated price: {new_price}")
else:
print("no submitted trade, place order")
if (action == Action.Buy and not is_hold_future(api, contract)) or \
(action == Action.Sell and is_hold_future(api, contract)):
order = api.Order(
action=action, # 買賣別
price=contract.reference, # 價格
quantity=1, # 數量
price_type=FuturesPriceType.LMT, # 委託價格類別
order_type=OrderType.ROD, # 委託條件
octype=FuturesOCType.Auto, # 倉別
account=api.futopt_account # 下單帳號
)
trade = api.place_order(contract, order)
print("place order success")
print(trade)
else:
if action == Action.Buy:
print(f"you are holding future contract {contract.name}, does not need to buy")
else:
print(f"you are not holding future contract {contract.name}, does not need to sell")
執行程式
切換到專案目錄下後,一樣使用以下命令執行程式,
cd alpha-investment
PYTHONPATH=./ python ./lambda_function/future_rollover.py
執行後可看到 2 個策略回覆的結果,第 1 個策略 MustBuyIfSettlementThisWeekStrategy 因為執行的日期是 2025-11-05,非結算週,所以 return False,
第 2 個策略 LowerThanMedianOfXDaysStrategy 查出來的歷史價差中位數是 -3,目前是正價差 21,所以也是 return False,最終就是判斷不需要轉倉。

今天這版的程式會放在我的 GitHub – tshine73/alpha-investment at v2 上。
下一步
就是要正式開始轉倉交易啦,我想把轉倉的執行放在 lambda 上做,所以下一篇會在來講講如何部署在 lambda 上!