欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

DilphinDB使用案例11:动量交易策略

程序员文章站 2022-03-21 09:00:59
...
  • 动量策略

    动量策略是最著名的长短期股票策略之一。

    自从Jegadeesh和Titman(1993)首次提出这个概念以来,它广泛出现在学术研究和销售方面的著作中。

    投资者在动量策略中相信,个股中,过去的赢家将超越过去的输家。

    最常用的动量因素是股票出去最近一个月,在过去12个月的收益。

    在学术出版物中,动量策略通常是一个月调整一次且持有期也是一个月。

    在本例中, 我们每天重新平衡我们的投资组合的1/21,并持有新份额21天。为简单起见,我们不考虑交易成本。

  • 加载数据并整理

  • 加载股票数据
    # 载入股票数据
    CH = ploadText("D:/DolphinDB/Data/CHstock1990_2018.csv")
    

    DilphinDB使用案例11:动量交易策略

  • 整理数据并计算动量信号
    # 计算动量信号
    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)
    

    DilphinDB使用案例11:动量交易策略

    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)
    

    DilphinDB使用案例11:动量交易策略

    筛选条件是,动量信号值无缺失、当日是正交易量、动量信号无缺失、股价大于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股数据不同,后续重新构建一个数据集再把这块补上