종종 친구들이 전략에 대해 논의하는 몇 가지 성능 지표 알고리즘이 있습니다. FMZ의 API 문서에서도 공개된 알고리즘이 있습니다. 그러나 논평없이 이해가 안되는 부분이 있습니다. 이 기사는 이 알고리즘을 분석하기 위해 당신과 함께합니다. 이 기사를 읽은 후 샬프율, 최대 회수율, 수익률과 같은 개념 계산, 논리 등에 대해 좀 더 명확한 이해가 있어야합니다.
우리는 자바스크립트 언어로 작성된 코드를 직접 소스에 올립니다. FMZ의 검색 시스템도 이 알고리즘을 사용하여 자동으로 검색 성능 데이터를 생성합니다.
function returnAnalyze(totalAssets, profits, ts, te, period, yearDays)
계산 함수이기 때문에 입력, 출력, 출력, 출력, 출력, 출력, 출력, 출력, 출력.
totalAssets, profits, ts, te, period, yearDays
총자산 이 매개 변수는 전략이 실행될 때 초기 자산 총입니다.
수익
이 매개 변수는 이 원자 데이터를 중심으로 일련의 성능 지표 계산이 이루어지기 때문에 매우 중요한 매개 변수이다. 이 매개 변수는 2차원 대수군이며, 형식은 예를 들어:[[timestamp1, profit1], [timestamp2, profit2], [timestamp3, profit3], ....., [timestampN, profitN]]
, 이 returnAnalyze 함수는 각 순간의 수익을 기록하는 시간 순서를 필요로 하는 데이터 구조이다. timestamp1에서 timestampN까지는 시간 순서로 멀리서 가까이서 있다. 각 시간점에 수익값이 있다. 예를 들어, 수익 기록의 세 번째 시간점은 [timestamp3, profit3]이다. FMZ 라인 리코딩 시스템에서 이 profits 집합 데이터 리코딩은 테스트 시스템에서 이 함수에게 제공된다.
ts
이 글의 시작시간은
te 이 글은 한글로 번역되어 있습니다.
기간 미리 초 수준으로 계산 주기가 있습니다.
yearDays 한 해 동안 거래되는 날.
이제 이 함수의 출력을 함께 보겠습니다.
return {
totalAssets: totalAssets,
yearDays: yearDays,
totalReturns: totalReturns,
annualizedReturns: annualizedReturns,
sharpeRatio: sharpeRatio,
volatility: volatility,
maxDrawdown: maxDrawdown,
maxDrawdownTime: maxDrawdownTime,
maxAssetsTime: maxAssetsTime,
maxDrawdownStartTime: maxDrawdownStartTime,
winningRate: winningRate
}
입력과 출력을 알고 나면 함수가 무엇을 하는지 알 수 있다. 간단히 말하면, 함수에게 원자록을 주면 됩니다. 예를 들어, 이득 통계 배열. 함수는 당신에게 결과를 계산하여 재검토 성과를 보여줍니다.
다음에는 코드가 어떻게 계산되는지 살펴볼 것입니다.
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이며, 차이는 각 데이터의 각각 합의 평균의 차이의 제곱의 합의 평균입니다.
유행률: 연령으로 계산할 때, 변동률은 표준편이다.
이러한 개념과 계산 수식을 이해하면 함수에서 샬프 계산에 관한 부분도 한눈에 분명해집니다. 샤프 계산 공식 계산 샤프 비율: (년차 수익률 - 위험 없는 금리율) / 표준 격차
이 모든 것을 어떻게 할 수 있을까요?