DilphinDB使用案例11:动量交易策略
程序员文章站
2022-03-21 09:00:59
...
-
动量策略
动量策略是最著名的长短期股票策略之一。
自从Jegadeesh和Titman(1993)首次提出这个概念以来,它广泛出现在学术研究和销售方面的著作中。
投资者在动量策略中相信,个股中,过去的赢家将超越过去的输家。
最常用的动量因素是股票出去最近一个月,在过去12个月的收益。
在学术出版物中,动量策略通常是一个月调整一次且持有期也是一个月。
在本例中, 我们每天重新平衡我们的投资组合的1/21,并持有新份额21天。为简单起见,我们不考虑交易成本。
-
加载数据并整理
-
加载股票数据
# 载入股票数据 CH = ploadText("D:/DolphinDB/Data/CHstock1990_2018.csv")
-
整理数据并计算动量信号
# 计算动量信号 def loadPriceData(inData){ CHstocks = select TS_CODE, TRADE_date, abs(open) as PRC, vol as VOL,close/open-1 as RET from inData where weekday(trade_date) between 1:5, isValid(open), isValid(VOL) order by ts_code, trade_date CHstocks = select ts_code, trade_date, PRC, VOL, RET, cumprod(1+RET) as cumretIndex from CHstocks context by ts_code return select ts_code, trade_date, PRC, VOL, RET, move(cumretIndex,21)\move(cumretIndex,252)-1 as signal from CHstocks context by ts_code } priceData = loadPriceData(CH)
从
SQL
语句中可以看到,数据库字段不区分大小写。一般的数据库
SQL
语言是不区分大小写的,但是DolphinDB
区分大小写,sql关键字只能用小写。这里区分大小写指的是sql
关键字。 -
释放内存占用
# 释放内存 undef(`CH, VAR) # undef函数释放对象需要是字符串标量或向量,所以在CH前加上`
-
为动量策略生成投资组合
-
筛选个股
# 筛选个股 def genTradables(indata){ return select trade_date, ts_code, signal from indata where PRC>5, VOL>0, isValid(signal) order by trade_date } tradables = genTradables(priceData)
筛选条件是,动量信号值无缺失、当日是正交易量、动量信号无缺失、股价大于5元。
-
计算每日收益
# WtScheme=1表示等权重 ,WtScheme=2表示值权重 def formPortfolio(startDate, endDate, tradables, holdingDays, groups, WtScheme){ ports = select trade_date, ts_code, rank(signal,,groups) as rank, count(ts_code) as symCount, 0.0 as wt from tradables where trade_date between startDate:endDate context by trade_date having count(ts_code) >= 100 if (WtScheme == 1){ update ports set wt = -1.0\count(ts_code)\holdingDays where rank=0 context by trade_date update ports set wt = 1.0\count(ts_code)\holdingDays where rank=groups-1 context by trade_date } else if (WtScheme == 2){ # 缺数据未计算 } return select ts_code, trade_date as tranche, wt from ports where wt != 0 order by ts_code, trade_date } startDate = 1996.01.01 endDate = 2018.01.01 holdingDays = 21 groups =10 ports = formPortfolio(startDate, endDate, tradables, holdingDays, groups, 1) dailyRtn = select trade_date, ts_code, RET as dailyRet from priceData where trade_date between startDate:endDate
根据动量信号,制定10组可交易股票。只保留2个最极端的群体(赢家和输家)。假设我们总是想在21天内,每天多头1美元和空头$1,所以我们每天在赢家组多头$1/21,在输家组每天空头$1/21。在每组中,我们可以使用等权重或值权重, 来计算投资组合形成日期上每个股票的权重。
-
21天内每支股票利润走势
# 计算每支个股21天损益 def calcStockPnL(ports, dailyRtn, holdingDays, endDate, lastDays){ ages = table(1..holdingDays as age) dates = sort distinct ports.tranche dictDateIndex = dict(dates, 1..dates.size()) dictIndexDate = dict(1..dates.size(), dates) pos = select dictIndexDate[dictDateIndex[tranche]+age] as trade_date, ts_code, tranche, age, take(0.0,size age) as ret, wt as expr, take(0.0,size age) as pnl from cj(ports,ages) where isValid(dictIndexDate[dictDateIndex[tranche]+age]) and dictIndexDate[dictDateIndex[tranche]+age]<=min(lastDays[ts_code], endDate) update pos set ret = RET from ej(pos, dailyRtn,`trade_date`ts_code) update pos set expr = expr*cumprod(1+ret) from pos context by ts_code, tranche update pos set pnl = expr*ret/(1+ret) return pos } lastDaysTable = select max(trade_date) as date from priceData group by ts_code lastDays = dict(lastDaysTable.ts_code, lastDaysTable.date) undef(`priceData, VAR) stockPnL = calcStockPnL(ports, dailyRtn, holdingDays, endDate, lastDays)
-
计算投资组合的利润/损失,并绘图
# 计算总体收益并绘图 portPnL = select sum(pnl) as pnl from stockPnL group by trade_date portPnL = select * from portPnL order by trade_date plot(cumsum(portPnL.pnl) as cumulativeReturn,portPnL.trade_date, "Cumulative Returns of the Momentum Strategy")
最后两部分还没完全搞懂,主要是示例中所用美股数据字段与A股数据不同,后续重新构建一个数据集再把这块补上