import pandas as pd
import numpy as np
import datetime
import tejapi
import time
import os
import warnings
warnings.filterwarnings('ignore')
# tej_key
tej_key ='your key'
tejapi.ApiConfig.api_key = tej_key
os.environ['TEJAPI_BASE'] = "https://api.tej.com.tw"
os.environ['TEJAPI_KEY'] = tej_key
# date
start='2022-10-15'
end='2022-11-05'
os.environ['mdate'] = '20221015 20221105'
tz = 'UTC'
start_dt, end_dt = pd.Timestamp(start, tz = tz), pd.Timestamp(end, tz = tz)
# calendar
calendar_name='TEJ'
# bundle_name
bundle_name = 'tquant'
# ticker
os.environ['ticker'] = "1216 2330 2327 IR0001 5844"
!zipline ingest -b tquant
Merging daily equity files:
[2023-09-25 02:10:50.408398] INFO: zipline.data.bundles.core: Ingesting tquant.
from zipline.api import *
from zipline import run_algorithm
from zipline.finance import commission, slippage
from zipline.utils.calendar_utils import get_calendar
from zipline.utils.run_algo import (get_transaction_detail,
get_record_vars)
from logbook import Logger, StderrHandler, INFO
# 設定log顯示方式
log_handler = StderrHandler(format_string='[{record.time:%Y-%m-%d %H:%M:%S.%f}]: ' +
'{record.level_name}: {record.func_name}: {record.message}',
level=INFO)
log_handler.push_application()
log = Logger('Algorithm')
取得未完全成交的訂單資料
Parameters:
asset:zipline.assets.Asset
Asset
物件(zipline.assets.Asset
,例如:Equity(0 [1101]),透過symbol("1101")
可將 symbol 轉成Asset
物件),則僅回傳該股票的未完全成交訂單資料。Returns:
回傳未完全成交的訂單資料,資料型態為dict[list[Order]]
zipline.finance.order.Order
)。Event({'id': '3096bfae27824859a4f9aba7a75fb31a', 'dt': Timestamp('2022-10-17 05:30:00+0000', tz='UTC'), 'reason': None, 'created': Timestamp('2022-10-17 05:30:00+0000', tz='UTC'), 'amount': 1500000, 'filled': 0, 'commission': 0, 'stop': None, 'limit': None, 'stop_reached': False, 'limit_reached': False, 'sid': Equity(1 [1216]), 'status': <ORDER_STATUS.OPEN: 0>})
orders
的說明:lecture/TSMC buy and hold strategy.ipynb。取消某筆訂單。
Parameters:
order_param:str or Order
zipline.finance.order.Order.id
)或 order 物件(zipline.finance.order.Order
)來指定欲取消的訂單。zipline.finance.order.Order
):zipline.api.get_open_orders
取得。zipline.api.get_order(order_id)
取得。get_open_orders
與cancel_order
兩個函數通常在handle_data
階段使用。from zipline.api import cancel_order, get_open_orders
或from zipline.api import *
。
若訂單在建立後的下一個交易日未能完全成交,希望取消訂單。
在以下這個範例,我們設計了 PART A 及 PART B 兩部分程式碼:
PART A
get_open_orders
檢查並用cancel_order
取消還沒成交的訂單。def handle_data(context, data):
open_orders = get_open_orders()
for asset in open_orders:
for o in open_orders[asset]:
cancel_order(o)
...
設定滑價模型:set_slippage(slippage.VolumeShareSlippage(volume_limit=0.025, price_impact=0.1))
,並限制買賣量最高只能是當天實際成交量的 2.5%。
設定交易:
data.is_stale
的狀態。def handle_data(context, data):
...
print(get_datetime(), symbol('2327'), 'is_stale =', data.is_stale(symbol('2327')))
if context.i == 0: # 2022-10-17
order(symbol('1216'), 1500000)
if context.i == 2: # 2022-10-19
order(symbol('2327'), 1000)
if context.i == 3: # 2022-10-20
order(symbol('2327'), 1000)
...
PART B
在每天下單後,檢查 data.is_stale = True 的股票,並取消該股票所有的訂單。
def handle_data(context, data):
...
open_orders = get_open_orders()
for asset in open_orders:
if data.is_stale(asset):
for o in open_orders[asset]:
cancel_order(o)
...
data.is_stale(assets):¶
- 若該股票未下市、曾經有交易紀錄且當天 volume = 0 則回傳 True,否則 False。
- 通常當股票當天暫停交易或是成交量為 0 時會回傳 True,這種情況下 zipline 是不會交易的。
Parameters:
asset:zipline.assets.Asset or iterable of zipline.assets.Asset,該股票的Asset
物件(例如:Equity(0 [1101]))。Return type:
bool or pd.Series[bool]
def initialize(context):
context.i = 0
context.tickers = ['1216', '2330', '2327']
context.asset = [symbol(ticker) for ticker in context.tickers]
set_slippage(slippage. VolumeShareSlippage(volume_limit=0.025, price_impact=0.1))
set_commission(commission.PerDollar(cost = commission_cost))
set_benchmark(symbol('IR0001'))
def handle_data(context, data):
# PART A---------------------------------------------------------------------------------------
open_orders = get_open_orders()
for asset in open_orders:
for o in open_orders[asset]:
cancel_order(o)
print(get_datetime(), symbol('2327'), 'is_stale =', data.is_stale(symbol('2327')))
if context.i == 0: # 2022-10-17
order(symbol('1216'), 1500000)
if context.i == 2: # 2022-10-19
order(symbol('2327'), 1000)
if context.i == 3: # 2022-10-20
order(symbol('2327'), 1000)
# PART B---------------------------------------------------------------------------------------
open_orders = get_open_orders()
for asset in open_orders:
if data.is_stale(asset):
for o in open_orders[asset]:
cancel_order(o)
record(close=data.current(context.asset, 'close'))
record(volume=data.current(context.asset, 'volume')*1000)
context.i += 1
commission_cost = 0.001425
capital_base = 1e8
performance = run_algorithm(start=start_dt,
end=end_dt,
initialize=initialize,
handle_data=handle_data,
capital_base=capital_base,
trading_calendar=get_calendar(calendar_name),
bundle=bundle_name)
closing_price = tejapi.fastget('TWN/APIPRCD',
coid=['1216'],
opts={'columns':['mdate','coid','open_d','close_d','vol']},
mdate={'gte':start,'lte':end },
paginate=True)
closing_price['vol'] = closing_price['vol'] * 1000
positions, transactions, orders = get_transaction_detail(performance)
[2023-09-25 02:10:52.690774]: INFO: handle_simulation_end: Simulated 15 trading days first open: 2022-10-17 01:01:00+00:00 last close: 2022-11-04 05:30:00+00:00
2022-10-17 05:30:00+00:00 Equity(1 [2327]) is_stale = False 2022-10-18 05:30:00+00:00 Equity(1 [2327]) is_stale = False 2022-10-19 05:30:00+00:00 Equity(1 [2327]) is_stale = False 2022-10-20 05:30:00+00:00 Equity(1 [2327]) is_stale = True 2022-10-21 05:30:00+00:00 Equity(1 [2327]) is_stale = True 2022-10-24 05:30:00+00:00 Equity(1 [2327]) is_stale = True 2022-10-25 05:30:00+00:00 Equity(1 [2327]) is_stale = True 2022-10-26 05:30:00+00:00 Equity(1 [2327]) is_stale = True 2022-10-27 05:30:00+00:00 Equity(1 [2327]) is_stale = True 2022-10-28 05:30:00+00:00 Equity(1 [2327]) is_stale = True 2022-10-31 05:30:00+00:00 Equity(1 [2327]) is_stale = False 2022-11-01 05:30:00+00:00 Equity(1 [2327]) is_stale = False 2022-11-02 05:30:00+00:00 Equity(1 [2327]) is_stale = False 2022-11-03 05:30:00+00:00 Equity(1 [2327]) is_stale = False 2022-11-04 05:30:00+00:00 Equity(1 [2327]) is_stale = False
# vol:實際成交量,單位為股。
closing_price.query('(coid == "1216") & (mdate == "2022-10-18")')
mdate | coid | open_d | close_d | vol | |
---|---|---|---|---|---|
1 | 2022-10-18 | 1216 | 66.0 | 65.3 | 6494000.0 |
orders.query('symbol == "1216"')
sid | symbol | id | dt | reason | created | amount | filled | commission | stop | limit | stop_reached | limit_reached | asset | status | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2022-10-17 13:30:00+08:00 | 0 | 1216 | dc9d0e5a7db945dab328108520feabfb | 2022-10-17 13:30:00+08:00 | None | 2022-10-17 13:30:00+08:00 | 1500000 | 0 | 0.000000 | None | None | False | False | Equity(0 [1216]) | 0 |
2022-10-18 13:30:00+08:00 | 0 | 1216 | dc9d0e5a7db945dab328108520feabfb | 2022-10-18 13:30:00+08:00 | None | 2022-10-17 13:30:00+08:00 | 1500000 | 162350 | 15108.017567 | None | None | False | False | Equity(0 [1216]) | 2 |
transactions
sid | symbol | amount | dt | price | order_id | asset | commission | |
---|---|---|---|---|---|---|---|---|
2022-10-18 13:30:00+08:00 | 0 | 1216 | 162350 | 2022-10-18 13:30:00+08:00 | 65.304081 | dc9d0e5a7db945dab328108520feabfb | Equity(0 [1216]) | None |
orders.query('symbol == "2327"')
sid | symbol | id | dt | reason | created | amount | filled | commission | stop | limit | stop_reached | limit_reached | asset | status | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2022-10-19 13:30:00+08:00 | 1 | 2327 | 948a3e20ad1c4158a8233cc604bd21af | 2022-10-19 13:30:00+08:00 | None | 2022-10-19 13:30:00+08:00 | 1000 | 0 | 0.0 | None | None | False | False | Equity(1 [2327]) | 0 |
2022-10-20 13:30:00+08:00 | 1 | 2327 | 948a3e20ad1c4158a8233cc604bd21af | 2022-10-20 13:30:00+08:00 | None | 2022-10-19 13:30:00+08:00 | 1000 | 0 | 0.0 | None | None | False | False | Equity(1 [2327]) | 2 |
2022-10-20 13:30:00+08:00 | 1 | 2327 | d3fa16e044514cc8b7e046d72a0812b8 | 2022-10-20 13:30:00+08:00 | None | 2022-10-20 13:30:00+08:00 | 1000 | 0 | 0.0 | None | None | False | False | Equity(1 [2327]) | 2 |
希望未成交訂單不要保留超過10天。
在以下這個範例,我們設計了 PART C 的程式碼:
取消訂單邏輯:
每天利用get_open_orders
產出未完全成交的訂單。
針對上述訂單逐筆進行以下判斷:若距離訂單建立日(zipline.finance.order.Order.created
)達10個交易日(不含建立日),但還沒有完全成交時取消該訂單。
calendar_name='TEJ'
def handle_data(context, data):
open_orders = get_open_orders()
for asset in open_orders:
for o in open_orders[asset]:
waiting_time = (len(get_calendar(calendar_name).sessions_in_range(o.created, get_datetime())))
if waiting_time == 10:
cancel_order(o)
...
設定交易:
在10/17 long 1000 股的 1216 股票,並設定 stop_price = 66。
在10/20 long 1000 股的 1216 股票,並設定 stop_price = 65.5。
def handle_data(context, data):
...
if context.i == 0: # 2022-10-17
order(symbol('1216'), 1000, stop_price = 66)
if context.i == 3: # 2022-10-20
order(symbol('1216'), 1000, stop_price = 65.5)
...
def initialize(context):
context.i = 0
context.tickers = ['1216', '2330', '2327']
context.asset = [symbol(ticker) for ticker in context.tickers]
set_slippage(slippage. VolumeShareSlippage(volume_limit=0.025, price_impact=0.1))
set_commission(commission.PerDollar(cost = commission_cost))
set_benchmark(symbol('IR0001'))
def handle_data(context, data):
#PART C
open_orders = get_open_orders()
for asset in open_orders:
for o in open_orders[asset]:
waiting_time = (len(get_calendar(calendar_name).sessions_in_range(o.created, get_datetime())))
if waiting_time == 10:
cancel_order(o)
if context.i == 0: # 2022-10-17
order(symbol('1216'), 1000, stop_price = 66)
if context.i == 3: # 2022-10-20
order(symbol('1216'), 1000, stop_price = 65.5)
record(close=data.current(context.asset, 'close'))
record(volume=data.current(context.asset, 'volume'))
context.i += 1
commission_cost = 0.001425
capital_base = 1e8
performance = run_algorithm(start=start_dt,
end=end_dt,
initialize=initialize,
handle_data=handle_data,
capital_base=capital_base,
trading_calendar=get_calendar(calendar_name),
bundle=bundle_name)
closing_price = tejapi.get('TWN/APIPRCD',
coid=['1216'],
opts={'columns':['mdate','coid','close_d']},
mdate={'gte':start,'lte':end },
paginate=True)
positions, transactions, orders = get_transaction_detail(performance)
[2023-09-25 02:10:52.891546]: INFO: handle_simulation_end: Simulated 15 trading days first open: 2022-10-17 01:01:00+00:00 last close: 2022-11-04 05:30:00+00:00
zipline.finance.order.Order.created
)取得訂單建立時間,再用get_datetime()
取得當天時間,接著用 get_calendar(calendar_name).sessions_in_range(start, end)
算出經過了多少個交易日,最後建立迴圈並逐日檢查並取消等待太久的訂單。closing_price.query('(mdate <= "2022-11-01")')
mdate | coid | close_d | |
---|---|---|---|
None | |||
0 | 2022-10-17 | 1216 | 65.9 |
1 | 2022-10-18 | 1216 | 65.3 |
2 | 2022-10-19 | 1216 | 65.3 |
3 | 2022-10-20 | 1216 | 64.7 |
4 | 2022-10-21 | 1216 | 64.1 |
5 | 2022-10-24 | 1216 | 65.1 |
6 | 2022-10-25 | 1216 | 65.5 |
7 | 2022-10-26 | 1216 | 65.6 |
8 | 2022-10-27 | 1216 | 65.8 |
9 | 2022-10-28 | 1216 | 65.8 |
10 | 2022-10-31 | 1216 | 65.5 |
11 | 2022-11-01 | 1216 | 66.1 |
orders.query('created.dt.strftime("%Y-%m-%d") == "2022-10-17"')
sid | symbol | id | dt | reason | created | amount | filled | commission | stop | limit | stop_reached | limit_reached | asset | status | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2022-10-17 13:30:00+08:00 | 0 | 1216 | 34653855667b4281a12db30677740148 | 2022-10-17 13:30:00+08:00 | None | 2022-10-17 13:30:00+08:00 | 1000 | 0 | 0.0 | 66.0 | None | False | False | Equity(0 [1216]) | 0 |
2022-10-31 13:30:00+08:00 | 0 | 1216 | 34653855667b4281a12db30677740148 | 2022-10-31 13:30:00+08:00 | None | 2022-10-17 13:30:00+08:00 | 1000 | 0 | 0.0 | 66.0 | None | False | False | Equity(0 [1216]) | 2 |
在10/20下的訂單,stop_price = 65.5,在10/25就成交,並沒有等待超過十天,因此不會被 PART C 這段程式給取消掉。
closing_price.query('(mdate <= "2022-10-25") & (mdate >= "2022-10-20")')
mdate | coid | close_d | |
---|---|---|---|
None | |||
3 | 2022-10-20 | 1216 | 64.7 |
4 | 2022-10-21 | 1216 | 64.1 |
5 | 2022-10-24 | 1216 | 65.1 |
6 | 2022-10-25 | 1216 | 65.5 |
orders.query('created.dt.strftime("%Y-%m-%d") == "2022-10-20"')
sid | symbol | id | dt | reason | created | amount | filled | commission | stop | limit | stop_reached | limit_reached | asset | status | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2022-10-20 13:30:00+08:00 | 0 | 1216 | 28ccb816137346b7b6c8b4e26639cb8d | 2022-10-20 13:30:00+08:00 | None | 2022-10-20 13:30:00+08:00 | 1000 | 0 | 0.0000 | 65.5 | None | False | False | Equity(0 [1216]) | 0 |
2022-10-25 13:30:00+08:00 | 0 | 1216 | 28ccb816137346b7b6c8b4e26639cb8d | 2022-10-25 13:30:00+08:00 | None | 2022-10-20 13:30:00+08:00 | 1000 | 1000 | 93.3375 | 65.5 | None | True | False | Equity(0 [1216]) | 1 |
transactions
sid | symbol | amount | dt | price | order_id | asset | commission | |
---|---|---|---|---|---|---|---|---|
2022-10-25 13:30:00+08:00 | 0 | 1216 | 1000 | 2022-10-25 13:30:00+08:00 | 65.5 | 28ccb816137346b7b6c8b4e26639cb8d | Equity(0 [1216]) | None |