基于聚宽量化交易平台实现量化交易策略
一、入門量化策略
JoinQuant聚寬API文檔:https://www.joinquant.com/help/api/help?name=api
1、獲取要操作的股票或指數成分股
# 導入函數庫
import jqdata
# 初始化函數,設定基準
def initialize(context):
# 定義一個全局變量, 保存要操作的股票
# 方式一:操作一只股票
# g.security = '601318.XSHG' # 中國平安股票
# 方式二:操作多只股票
# g.security = ['601101.XSHG', '601106.XSHG']
# 方式三:操作指數成分股
g.security = get_index_stocks('000300.XSHG') # 滬深300
print(g.security)
執行顯示滬深300指數成分股:
2、開啟動態復權模式(真實價格)
開啟真實價格回測功能很簡單,只需一步即可搞定:在initialize中使用set_option。
(1)開啟動態復權測試
# 導入函數庫
import jqdata
# 初始化函數,設定基準
def initialize(context):
# 定義一個全局變量, 保存要操作的股票
# 方式一:操作一只股票
# g.security = '601318.XSHG' # 中國平安股票
# 方式二:操作多只股票
# g.security = ['601101.XSHG', '601106.XSHG']
# 方式三:操作指數成分股
g.security = get_index_stocks('000300.XSHG') # 滬深300
set_option('use_real_price', True)
由于滬深300不存在分紅和股票拆合,顯示效果和上圖一致。
(2)開啟動態復權(真實價格)模式對模擬交易的影響
在模擬交易中,在未開啟動態復權(真實價格)模式時,我們是使用基于模擬交易創建日期的后復權價格。
后復權模式示意圖如下圖所示:
不開啟真實價格模擬盤的運算結果是沒有錯誤,只是會理解起來更費勁一些。
如果想知道今天的真實價格,還需知道模擬創建的日期,并進行復權計算。為了讓用戶使用更便于理解、更真實的模擬系統,強烈建議開啟動態復權(真實價格)模式。開啟方式:在代碼中調用set_option('use_real_price', True)。
開啟動態復權(真實價格)模式示意圖如下圖所示:
開啟動態復權(真實)模式后,看到的價格都是最新的,每到新的一天, 如果持倉中有股票發生了拆合或者分紅或者其他可能影響復權因子的情形, 會根據復權因子自動調整股票的數量.。但不要跨日期緩存這些 API 返回的結果。
3、設置傭金/印花稅
交易稅費包含券商手續費和印花稅。可以通過 set_order_cost 來設置具體的交易稅費的參數。
set_order_cost(cost, type, ref=None)
修改代碼如下所示:
# 導入函數庫
import jqdata
# 初始化函數,設定基準
def initialize(context):
# 定義一個全局變量, 保存要操作的股票
# 方式一:操作一只股票
# g.security = '601318.XSHG' # 中國平安股票
# 方式二:操作多只股票
# g.security = ['601101.XSHG', '601106.XSHG']
# 方式三:操作指數成分股
g.security = get_index_stocks('000300.XSHG') # 滬深300
set_option('use_real_price', True)
# 股票類每筆交易時的手續費是:買入時傭金萬分之三,賣出時傭金萬分之三加千分之一印花稅, 每筆交易傭金最低扣5塊錢
set_order_cost(
OrderCost( # OrderCost 對象
open_tax=0, # 買入時印花稅
close_tax=0.001, # 賣出時印花稅
open_commission=0.0003, # 買入時傭金
close_commission=0.0003, # 賣出時傭金
close_today_commission=0, # 平今日倉傭金
min_commission=5 # 最低傭金
),
type='stock' # 股票
)
(1)券商手續費
中國A股市場目前為雙邊收費,券商手續費系默認值為萬分之三,即0.03%,最少5元。
(2)印花稅
印花稅對賣方單邊征收,對買方不再征收,系統默認為千分之一,即0.1%。
(3)參數
cost: OrderCost 對象
open_tax,買入時印花稅 (只股票類標的收取,基金與期貨不收)
close_tax,賣出時印花稅 (只股票類標的收取,基金與期貨不收)
open_commission,買入時傭金,申購場外基金的手續費
close_commission, 賣出時傭金,贖回場外基金的手續費
close_today_commission, 平今倉傭金
min_commission, 最低傭金,不包含印花稅
type: 股票、場內基金、場內交易的貨幣基金、分級A基金、分級B基金、分級母基金、金融期貨、期貨、債券基金、股票基金、QDII 基金、場外交易的貨幣基金、混合基金、場外基金,'stock'/ 'fund' / 'mmf' /'fja'/'fjb'/ 'fjm'/ 'index_futures' / 'futures' / 'bond_fund' / 'stock_fund' / 'QDII_fund' / 'money_market_fund' / ‘mixture_fund' / 'open_fund'
ref: 參考代碼,支持股票代碼/基金代碼/期貨合約代碼,以及期貨的品種,如 '000001.XSHE'/'510180.XSHG'/'IF1709'/'IF'/'000300.OF'
注意:針對特定的交易品種類別設置手續費時,必須將ref設為None;若針對特定的交易品種或者標的,需要將type設置為對應的交易品種類別,將ref設置為對應的交易品種或者標的。
(4)常用示例
# 股票類每筆交易時的手續費是:買入時傭金萬分之三,賣出時傭金萬分之三加千分之一印花稅, 每筆交易傭金最低扣5塊錢 set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003, close_today_commission=0, min_commission=5), type='stock') # 期貨類每筆交易時的手續費是:買入時萬分之0.23,賣出時萬分之0.23,平今倉為萬分之23 set_order_cost(OrderCost(open_tax=0, close_tax=0, open_commission=0.000023, close_commission=0.000023, close_today_commission=0.0023, min_commission=0), type='index_futures') # 單獨設置 000300.XSHG 的費用 set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003, close_today_commission=0, min_commission=5), type='stock', ref='000300.XSHG') # 設置所有期貨(包括金融指數期貨)的費用 set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003, close_today_commission=0, min_commission=5), type='futures') # 對 IF/IH/IC 三個品種有效 set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003, close_today_commission=0, min_commission=5), type='index_futures') # 單獨設置AU期貨品種的費用 set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003, close_today_commission=0, min_commission=5), type='futures', ref='AU') # 單獨設置AU1709合約的費用 set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003, close_today_commission=0, min_commission=5), type='futures', ref='AU1709')
二、單位時間運行策略函數
handle_data:該函數每個單位時間會調用一次, 如果按天回測,則每天調用一次,如果按分鐘,則每分鐘調用一次。
該函數依據的時間是股票的交易時間,即 9:30 - 15:00。 期貨應使用定時函數。
該函數在回測中的非交易日是不會觸發的(如回測結束日期為2016年1月5日,則程序在2016年1月1日-3日時,handle_data不會運行,4日繼續運行)。
對于使用當日開盤價撮合的日級模擬盤,在9:25集合競價完成時就可以獲取到開盤價,出于減少并發運行模擬盤數量的目的,我們會提前到9:27~9:30之間運行, 策略內獲取到邏輯時間(context.current_dt)仍然是 9:30。
# 導入函數庫
import jqdata
# 初始化函數,設定基準
def initialize(context):
# 定義一個全局變量, 保存要操作的股票
# 方式一:操作一只股票
# g.security = '601318.XSHG' # 中國平安股票
# 方式二:操作多只股票
# g.security = ['601101.XSHG', '601106.XSHG']
# 方式三:操作指數成分股
g.security = get_index_stocks('000300.XSHG') # 滬深300
set_option('use_real_price', True)
# 股票類每筆交易時的手續費是:買入時傭金萬分之三,賣出時傭金萬分之三加千分之一印花稅, 每筆交易傭金最低扣5塊錢
set_order_cost(
OrderCost( # OrderCost 對象
open_tax=0, # 買入時印花稅
close_tax=0.001, # 賣出時印花稅
open_commission=0.0003, # 買入時傭金
close_commission=0.0003, # 賣出時傭金
close_today_commission=0, # 平今日倉傭金
min_commission=5 # 最低傭金
),
type='stock' # 股票
)
def handle_data(context, data):
print('Hello')
執行效果如下所示:
1、獲取當前時間數據
get_current_data():獲取當前單位時間(當天/當前分鐘)的漲跌停價, 是否停牌,當天的開盤價等。
該方法返回值是一個dict, 其中 key 是股票代碼, value 是擁有最新價、漲停價、跌停價等屬性對象。
(1)返回字典key值對應value所擁有的屬性對象
value值對應的屬性對象:
last_price : 最新價
high_limit: 漲停價
low_limit: 跌停價
paused: 是否停止或者暫停了交易, 當停牌、未上市或者退市后返回 True
is_st: 是否是 ST(包括ST, *ST),是則返回 True,否則返回 False
day_open: 當天開盤價
name: 股票現在的名稱, 可以用這個來判斷股票當天是否是 ST, *ST, 是否快要退市
industry_code: 股票現在所屬行業代碼, 參見行業概念數據
(2)示例
def handle_data(context, data):
print(
get_current_data()['601318.XSHG'].name,
get_current_data()['601318.XSHG'].industry_code,
get_current_data()['601318.XSHG'].day_open,
get_current_data()['601318.XSHG'].high_limit,
get_current_data()['601318.XSHG'].low_limit,
)
輸出結果如下所示:
2、獲取歷史數據
attribute_history:獲取歷史數據,可查詢單個標的多個數據字段,返回數據格式為 DataFrame 或 Dict(字典)。
attribute_history(security, count, unit='1d',
fields=['open', 'close', 'high', 'low', 'volume', 'money'],
skip_paused=True, df=True, fq='pre')
查看某一支股票的歷史數據, 可以選這只股票的多個屬性,默認跳過停牌日期。當取天數據時, 不包括當天的, 即使是在收盤后;分鐘數據包括當前分鐘的數據;
def handle_data(context, data):
# print(
# get_current_data()['601318.XSHG'].name,
# get_current_data()['601318.XSHG'].industry_code,
# get_current_data()['601318.XSHG'].day_open,
# get_current_data()['601318.XSHG'].high_limit,
# get_current_data()['601318.XSHG'].low_limit,
# )
print(attribute_history(
'601318.XSHG', # 股票代碼
5 # 每天返回前5天的歷史數據
))
執行顯示效果如下:
3、按股數下單
按股數下單。
order(security, amount, style=None, side='long', pindex=0, close_today=False)
買賣標的。調用成功后, 您將可以調用[get_open_orders]取得所有未完成的交易, 也可以調用[cancel_order]取消交易。
(1)參數
- security: 標的代碼
- amount: 交易數量, 正數表示買入, 負數表示賣出
- style: 參見[OrderStyle](#OrderStyle), None代表MarketOrder - side: 'long'/'short',操作多單還是空單。默認為多單,**股票、基金暫不支持開空單**。
- pindex: 在使用set_subportfolios創建了多個倉位時,指定subportfolio 的序號, 從 0 開始, 比如 0 指定第一個 subportfolio, 1 指定第二個 subportfolio,**默認為0**。
- close_today: 平今字段,close_today: 平今字段,僅對上海國際能源中心,上海期貨交易所,中金所生效,其他交易所將會報錯(其他交易所沒有區分平今與平昨,均按照先開先平的方法處理)。
- 對上海國際能源中心,上海期貨交易所,中金所的標的:
- close_today = True, 只平今倉
- close_today = False, 優先平昨倉,昨倉不足部分平進倉 **返回** Order對象或者None, 如果創建訂單成功, 則返回Order對象, 失敗則返回None
(2)買入下單示例
def handle_data(context, data):
# 每天買入100股
order('601318.XSHG', 100)
顯示效果:
需要注意,開倉股票數量必須是100的整數倍,如果設置為110,會自動調整為100。
4、按價值下單
order_value(security, value, style=None, side='long', pindex=0, close_today=False)
(1)參數
- security: 股票名字
- value: 股票價值,value = 最新價 * 手數 * 保證金率(股票為1) * 乘數(股票為100)
- style: 參見[OrderStyle](#OrderStyle), None代表MarketOrder
- side: 'long'/'short',操作多單還是空單。默認為多單。默認為多單,**股票、基金暫不支持開空單**。
- pindex: 在使用set_subportfolios創建了多個倉位時,指定subportfolio 的序號, 從 0 開始, 比如 0為 指定第一個 subportfolio, 1 為指定第二個 subportfolio,**默認為0**。
- close_today: 平今字段,close_today: 平今字段,僅對上海國際能源中心,上海期貨交易所,中金所生效,其他交易所將會報錯(其他交易所沒有區分平今與平昨,均按照先開先平的方法處理)。
- 對上海國際能源中心,上海期貨交易所,中金所的標的:
- close_today = True, 只平今倉
- close_today = False, 優先平昨倉,昨倉不足部分平進倉 **返回** Order對象或者None, 如果創建委托成功, 則返回Order對象, 失敗則返回None
(2)示例
def handle_data(context, data):
# 每天花10000買股票
order_value('601318.XSHG', 10000)
顯示效果:
5、目標股數(買到數量)下單
order_target(security, amount, style=None, side='long', pindex=0, close_today=False)
買賣標的, 使最終標的的數量達到指定的amount,注意使用此接口下單時若指定的標的有未完成的訂單,則先前未完成的訂單將會被取消。
(1)參數
- security: 標的代碼
- amount: 期望的最終數量
- style: 參見[OrderStyle](#OrderStyle), None代表MarketOrder - side: 'long'/'short',操作多單還是空單。默認為多單。默認為多單,**股票、基金暫不支持開空單**。
- pindex: 在使用set_subportfolios創建了多個倉位時,指定subportfolio 的序號, 從 0 開始, 比如 0為 指定第一個 subportfolio, 1 為指定第二個 subportfolio,**默認為0**。
- close_today: 平今字段,close_today: 平今字段,僅對上海國際能源中心,上海期貨交易所,中金所生效,其他交易所將會報錯(其他交易所沒有區分平今與平昨,均按照先開先平的方法處理)。
- 對上海國際能源中心,上海期貨交易所,中金所的標的:
- close_today = True, 只平今倉
- close_today = False, 優先平昨倉,昨倉不足部分平進倉 **返回** Order對象或者None, 如果創建委托成功, 則返回Order對象, 失敗則返回None
(2)示例
# 賣出平安銀行所有股票
order_target('000001.XSHE', 0)
# 買入平安銀行所有股票到100股
order_target('000001.XSHE', 100)
6、目標價值下單
order_target_value(security, value, style=None, side='long', pindex=0, close_today=False)
調整標的倉位到value價值,金融期貨暫不支持該API。
注意使用此接口下單時若指定的標的有未完成的訂單,則先前未完成的訂單將會被取消。
(1)參數
- security: 標的名字 - value: 期望的標的最終價值,value = 最新價 * 手數 * 保證金率(股票為1) * 乘數(股票為100) - style: 參見[OrderStyle](#OrderStyle), None代表MarketOrder - side: 'long'/'short',操作多單還是空單。默認為多單。 - pindex: 在使用set_subportfolios創建了多個倉位時,指定subportfolio 的序號, 從 0 開始, 比如 0為 指定第一個 subportfolio, 1 為指定第二個 subportfolio,**默認為0**。
(2)示例
#賣出平安銀行所有股票
order_target_value('000001.XSHE', 0)
#調整平安銀行股票倉位到10000元價值
order_target_value('000001.XSHE', 10000)
三、實現一個簡單量化策略
1、策略內容
設置股票池為滬深300的所有成分股
如果當前股價小于10元/股且當前不持倉,則買入;
如果當前股價比買入時上漲了25%,則清倉止盈;
如果當前股價比買入時下跌了10%,則清倉止損。
2、Context——策略信息總覽
Context對象:策略信息總覽,包含賬戶、時間等信息。
(1)對象屬性
- subportfolios: 當前單個操作倉位的資金、標的信息,是一個SubPortfolio 的數組
- portfolio: 賬戶信息,即subportfolios 的匯總信息, Portfolio對象,單個操作倉位時,portfolio 指向 subportfolios[0]
- current_dt: 當前單位時間的開始時間, [datetime.datetime]對象
- previous_date: 前一個交易日, [datetime.date]對象, 注意, 這是一個日期, 是 date, 而不是 datetime
- universe: 查詢set_universe()設定的股票池, 比如: ['000001.XSHE', '600000.XSHG']
- run_params: 表示此次運行的參數, 有如下屬性
start_date: 回測/模擬開始日期, [datetime.date]對象
end_date: 回測/模擬結束日期, [datetime.date]對象
type: 運行方式, 如下四個字符串之一
'simple_backtest': 回測, 通過點擊'編譯運行'運行
'full_backtest': 回測, 通過點擊'運行回測'運行
'sim_trade': 模擬交易
'live_trade': 實盤交易
frequency: 運行頻率, 如下三個字符串之一
'day'
'minute'
'tick'
- 為了讓從其他平臺遷移過來的同學更順手的使用系統, 我們對此對象也做了和 [g] 一樣的處理:
- 可以添加自己的變量, 每次進程關閉時持久保存, 進程重啟時恢復.
- 以 '__' 開頭的變量不會被持久保存
- 如果添加的變量與系統的沖突, 將覆蓋掉系統變量, 如果想恢復系統變量, 請刪除自己的變量.
(2)示例
def handle_data(context, data):
# 執行下面的語句之后, context.portfolio 的整數 1
context.portfolio = 1
log.info(context.portfolio)
# 要恢復系統的變量, 只需要使用下面的語句即可
del context.portfolio
# 此時, context.portfolio 將變成賬戶信息.
log.info(context.portfolio.total_value)
3、策略實現——股價小于10元且當前不持倉則買入
# 導入函數庫
import jqdata
# 初始化函數,設定基準
def initialize(context):
g.security = get_index_stocks('000300.XSHG') # 滬深300
set_option('use_real_price', True)
# 股票類每筆交易時的手續費是:買入時傭金萬分之三,賣出時傭金萬分之三加千分之一印花稅, 每筆交易傭金最低扣5塊錢
set_order_cost(
OrderCost( # OrderCost 對象
open_tax=0, # 買入時印花稅
close_tax=0.001, # 賣出時印花稅
open_commission=0.0003, # 買入時傭金
close_commission=0.0003, # 賣出時傭金
close_today_commission=0, # 平今日倉傭金
min_commission=5 # 最低傭金
),
type='stock' # 股票
)
def handle_data(context, data):
# 要購買的股票
tobuy = []
# 遍歷滬深300成分股
for stock in g.security:
p = get_current_data()[stock].day_open # 開盤價
# 總倉位和可賣出倉位的差異是來自于T+1制度
amount = context.portfolio.positions[stock].total_amount # 這只股票總倉位(不包含掛單凍結倉位)
amount2 = context.portfolio.positions[stock].closeable_amount # 這只股票可賣出倉位
if p <= 10.0 and amount == 0:
# 符合條件加入購買列表
tobuy.append(stock)
# 每個股票投入的資金
cash_per_stock = context.portfolio.available_cash / len(tobuy)
for stock in tobuy:
# 根據價值買入
order_value(stock cash_per_stock)
4、策略實現——賣出實現止盈止損
一般在實現量化交易時,都是先賣后買。
# 導入函數庫
import jqdata
# 初始化函數,設定基準
def initialize(context):
# 定義一個全局變量, 保存要操作的股票
g.security = get_index_stocks('000300.XSHG') # 滬深300
set_option('use_real_price', True)
# 股票類每筆交易時的手續費是:買入時傭金萬分之三,賣出時傭金萬分之三加千分之一印花稅, 每筆交易傭金最低扣5塊錢
set_order_cost(
OrderCost( # OrderCost 對象
open_tax=0, # 買入時印花稅
close_tax=0.001, # 賣出時印花稅
open_commission=0.0003, # 買入時傭金
close_commission=0.0003, # 賣出時傭金
close_today_commission=0, # 平今日倉傭金
min_commission=5 # 最低傭金
),
type='stock' # 股票
)
def handle_data(context, data):
# 要購買的股票
tobuy = []
# 遍歷滬深300成分股
for stock in g.security:
p = get_current_data()[stock].day_open # 開盤價
amount = context.portfolio.positions[stock].total_amount # 這只股票總倉位(不包含掛單凍結倉位)
# 平均持倉成本
cost = context.portfolio.positions[stock].avg_cost
if amount > 0 and p >= cost * 1.25:
order_target(stock, 0) # 止盈,全部賣出
if amount > 0 and p <= cost * 0.9:
order_target(stock, 0) # 止損,全部賣出
if p <= 10.0 and amount == 0:
# 符合條件加入購買列表
tobuy.append(stock)
# 每個股票投入的資金
cash_per_stock = context.portfolio.available_cash / len(tobuy)
for stock in tobuy:
# 根據價值買入
order_value(stock, cash_per_stock)
執行效果如下所示:
紅線是基準收益,
藍線是策略收益,在這里可以很清楚看到策略收益小于基準收益,說明該交易策略不可行。
總結
以上是生活随笔為你收集整理的基于聚宽量化交易平台实现量化交易策略的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如果开发商降价卖房,我们要怎么办呢?
- 下一篇: 家里墙壁装修,电视背&rlm;景