Type/to search
8
Follow
1364
Followers
전략 백테스팅에서 샤프 비율, 최대 하락률, 수익률 및 기타 지표 알고리즘을 분석합니다.
Discussions
Created 2022-11-26 15:13:17  Updated 2023-09-18 20:21:39
 0
 2904

img

전략 백테스팅에서 샤프 비율, 최대 하락률, 수익률 및 기타 지표 알고리즘을 분석합니다.

그룹 회원들은 종종 전략의 성과 지표 알고리즘을 논의하며, FMZ API 문서에도 알고리즘이 공개되어 있습니다. 하지만 주석 없이 이해하기는 조금 어렵습니다. 이 글에서는 이 알고리즘을 분석해 보겠습니다. 이 글을 읽으면 샤프 비율, 최대값의 개념과 계산 논리를 더 잘 이해하실 수 있을 거라고 믿습니다. 인출, 수익률. 모두가 더 명확하게 이해합니다.

JavaScript로 작성된 소스 코드를 직접 살펴보겠습니다. FMZ의 백테스팅 시스템도 이 알고리즘을 사용하여 백테스팅 성과 데이터를 자동으로 생성합니다.

returnAnalyze 함수

function returnAnalyze(totalAssets, profits, ts, te, period, yearDays)

https://www.fmz.com/api#回测系统夏普算法

이는 계산 함수이므로 입력과 출력이 있어야 합니다. 먼저 함수의 입력을 살펴보겠습니다.

totalAssets, profits, ts, te, period, yearDays
  • totalAssets
    이 매개변수는 전략이 실행되기 시작할 때의 초기 총 자산입니다.

  • profits
    이 매개변수는 일련의 성과 지표 계산이 이 원시 데이터를 기반으로 하기 때문에 비교적 중요한 매개변수입니다. 이 매개변수는 2차원 배열이며 형식은 다음과 같습니다.[[timestamp1, profit1], [timestamp2, profit2], [timestamp3, profit3], ....., [timestampN, profitN]], returnAnalyze 함수는 각 순간의 반환을 시간순으로 기록하는 데이터 구조가 필요하다는 것을 알 수 있습니다. timestamp1부터 timestampN까지 시간적으로 먼 것부터 가까운 것 순으로 정렬되어 있습니다. 각 시점마다 이익가치가 있습니다. 예를 들어, 수익 기록의 세 번째 시점은 다음과 같습니다.[타임스탬프3, 이익3]. FMZ 라인의 백테스팅 시스템에서 수익 배열 데이터는 백테스팅 시스템에 의해 이 함수에 제공됩니다. 물론 수익 데이터를 직접 기록하여 이러한 배열 구조를 형성하는 경우 이 계산 함수에 제공할 수도 있습니다. 결과를 계산합니다.

  • ts
    백테스트의 시작 타임스탬프.

  • te
    백테스트의 종료 타임스탬프.

  • period
    밀리초 단위의 계산 주기.

  • yearDays
    1년 동안의 거래일.

다음으로, 이 함수의 출력을 살펴보겠습니다.

return { totalAssets: totalAssets, yearDays: yearDays, totalReturns: totalReturns, annualizedReturns: annualizedReturns, sharpeRatio: sharpeRatio, volatility: volatility, maxDrawdown: maxDrawdown, maxDrawdownTime: maxDrawdownTime, maxAssetsTime: maxAssetsTime, maxDrawdownStartTime: maxDrawdownStartTime, winningRate: winningRate }
  • totalAssets: 초기 순자산
  • yearDays: 거래일
  • totalReturns: 누적 반품율
  • annualizedReturns: 연간 수익률
  • sharpeRatio: 샤프 비율
  • 변동성: 변동성
  • maxDrawdown: 최대 되돌림
  • maxDrawdownTime: 최대 하락의 타임스탬프
  • maxAssetsTime: 최대 순가치의 타임스탬프
  • maxDrawdownStartTime: 최대 되돌림 시작 시간
  • winningRate: 승률

img

입력과 출력을 알았으니, 이제 이 함수가 무엇에 사용되는지 이해하게 되었습니다. 간단히 말해서, 이 함수에 수익 통계 배열과 같은 원시 레코드를 제공합니다. 이 함수는 백테스트 성과를 보여주기 위해 결과를 계산합니다.

다음으로, 코드가 어떻게 계산되는지 살펴보겠습니다.

javascript
function returnAnalyze(totalAssets, profits, ts, te, period, yearDays) { // force by days period = 86400000 // 一天的毫秒数,即 60 * 60 * 24 * 1000 if (profits.length == 0) { // 如果参数profits数组长度为0,无法计算直接返回空值 return null } var freeProfit = 0.03 // 无风险利率 ,也可以根据需求设置,例如国债年化3% var yearRange = yearDays * 86400000 // 一年所有累计的交易日的毫秒数 var totalReturns = profits[profits.length - 1][1] / totalAssets // 累计收益率 var annualizedReturns = (totalReturns * yearRange) / (te - ts) // 年华收益率,把收益统计的时间缩放到一年的尺度上得出的预期收益率 // MaxDrawDown var maxDrawdown = 0 // 初始化最大回撤变量为0 var maxAssets = totalAssets // 以初始净值赋值初始化最大资产变量 var maxAssetsTime = 0 // 初始化最大资产时刻的时间戳 var maxDrawdownTime = 0 // 初始化最大回撤时刻的时间戳 var maxDrawdownStartTime = 0 // 初始化最大回撤开始时刻的时间戳 var winningRate = 0 // 初始化胜率为0 var winningResult = 0 // 记录赢的次数 for (var i = 0; i < profits.length; i++) { // 遍历收益数组 if (i == 0) { if (profits[i][1] > 0) { // 如果第一个收益记录点,收益大于0,表示盈利 winningResult++ // 赢的次数累加1 } } else { // 如果不是第一个收益记录点,只要当前的点的收益,大于前一个时刻(收益点)的收益,表示盈利,赢的次数累加1 if (profits[i][1] > profits[i - 1][1]) { winningResult++ } } if ((profits[i][1] + totalAssets) > maxAssets) { // 如果该时刻的收益加初始净值大于记录出现过的最大资产,就更新最大资产数值,记录这个时刻的时间戳 maxAssets = profits[i][1] + totalAssets maxAssetsTime = profits[i][0] } if (maxAssets > 0) { // 当记录的最大资产数值大于0时,计算回撤 var drawDown = 1 - (profits[i][1] + totalAssets) / maxAssets if (drawDown > maxDrawdown) { // 如果当前回撤大于记录过的最大回撤,更新最大回撤、最大回撤时间等 maxDrawdown = drawDown maxDrawdownTime = profits[i][0] maxDrawdownStartTime = maxAssetsTime } } } if (profits.length > 0) { // 计算胜率 winningRate = winningResult / profits.length } // trim profits var i = 0 var datas = [] var sum = 0 var preProfit = 0 var perRatio = 0 var rangeEnd = te if ((te - ts) % period > 0) { rangeEnd = (parseInt(te / period) + 1) * period // 把rangeEnd处理为period的整倍数 } for (var n = ts; n < rangeEnd; n += period) { var dayProfit = 0.0 var cut = n + period while (i < profits.length && profits[i][0] < cut) { // 确保当时间戳不越界,数组长度也不越界 dayProfit += (profits[i][1] - preProfit) // 计算每天的收益 preProfit = profits[i][1] // 记录昨日的收益 i++ // 累加i用于访问下一个profits节点 } perRatio = ((dayProfit / totalAssets) * yearRange) / period // 计算当时年华的收益率 sum += perRatio // 累计 datas.push(perRatio) // 放入数组 datas } var sharpeRatio = 0 // 初始夏普比率为0 var volatility = 0 // 初始波动率为0 if (datas.length > 0) { var avg = sum / datas.length; // 求均值 var std = 0; for (i = 0; i < datas.length; i++) { std += Math.pow(datas[i] - avg, 2); // std用于计算后面的方差,后面的std / datas.length就是方差,求算数平方根就是标准差 } volatility = Math.sqrt(std / datas.length); // 当按年时,波动率就是标准差 if (volatility !== 0) { sharpeRatio = (annualizedReturns - freeProfit) / volatility // 夏普计算公式计算夏普率:(年华收益率 - 无风险利率) / 标准差 } } return { totalAssets: totalAssets, yearDays: yearDays, totalReturns: totalReturns, annualizedReturns: annualizedReturns, sharpeRatio: sharpeRatio, volatility: volatility, maxDrawdown: maxDrawdown, maxDrawdownTime: maxDrawdownTime, maxAssetsTime: maxAssetsTime, maxDrawdownStartTime: maxDrawdownStartTime, winningRate: winningRate } }

알고리즘은 전반적으로 복잡하지 않지만 미리 이해해야 할 몇 가지 개념이 있을 수 있습니다.

  • 변화:
    이는 수익 데이터의 집합으로 이해될 수 있습니다.
    표본 집합 1, 2, 3, 4, 5의 평균은 (1+2+3+4+5)/5=3이고 분산은 각 데이터 포인트와 그 차이의 제곱의 합입니다. 평균. 평균은 다음과 같습니다.[(1-3)^2+(2-3)^2+(3-3)^2+(4-3)^2+(5-3)^2]/5=2이고 분산은 2이다. .

  • 표준편차:
    분산의 제곱근을 구하면 표준 편차가 됩니다.

  • 휘발성:
    계산 규모가 연간화되면 변동성은 표준 편차가 됩니다.

이러한 개념과 계산 공식을 이해하면 함수의 샤프 계산 부분이 한눈에 명확해질 것입니다.
샤프 비율 계산 공식: (연간 수익률 - 무위험 이자율) / 표준편차

배웠어요?

Comment
All comments (0)
No data
No data
  • 1
iPhone Download
Forums
PINE Language
© 2015 - ∞ INVENTOR PTE LTD (SG)