Terdapat beberapa algoritma penanda prestasi yang sering dibincangkan oleh rakan sekerja dalam strategi, dan satu algoritma juga telah didedahkan dalam dokumen API FMZ. Tetapi tanpa komen, terdapat beberapa pemahaman yang tidak baik, artikel ini akan membawa anda untuk menganalisis algoritma ini, dan saya yakin setelah membaca artikel ini, anda harus mempunyai pemahaman yang lebih jelas mengenai perhitungan konsep dan logika seperti kadar sharp, penurunan maksimum, kadar pulangan dan lain-lain.
Kami memuat naik kod sumber secara langsung, kod yang ditulis dalam bahasa JavaScript. Sistem pengulangan FMZ juga menggunakan algoritma ini untuk menghasilkan data prestasi pengulangan secara automatik.
function returnAnalyze(totalAssets, profits, ts, te, period, yearDays)
Oleh kerana ia adalah fungsi pengiraan, maka pasti ada input, output. Mari kita lihat terlebih dahulu input fungsi:
totalAssets, profits, ts, te, period, yearDays
Total Aset Parameter ini adalah jumlah aset awal semasa dasar mula beroperasi.
keuntungan
Parameter ini adalah parameter yang lebih penting, kerana satu siri pengiraan penunjuk prestasi dijalankan di sekitar data mentah ini. Parameter ini adalah aritmatika dua dimensi, formatnya seperti:[[timestamp1, profit1], [timestamp2, profit2], [timestamp3, profit3], ....., [timestampN, profitN]]
, dapat dilihat bahawa fungsi returnAnalyze memerlukan struktur data yang mencatat susunan masa keuntungan setiap saat. Timestamp1 hingga timestampN adalah susunan masa dari jauh dan dekat. Setiap titik masa mempunyai nilai keuntungan. Sebagai contoh, titik masa ketiga dalam rekod keuntungan adalah [timestamp3, profit3]. Dalam sistem pengulangan dalam talian FMZ, kumpulan data keuntungan ini dikembalikan kepada fungsi ini oleh sistem pengukuran, tentu saja jika anda mencatat data keuntungan sendiri, pembentukan struktur aritmatika seperti itu juga boleh diberikan kepada fungsi pengiraan untuk mengira hasilnya.
ts Tempoh permulaan ujian semula adalah malam.
te Tempoh akhir ujian adalah malam.
tempoh Tempoh pengiraan pada tahap milidetik.
tahunDays Hari perdagangan setahun.
Sekarang mari kita lihat hasil daripada fungsi ini:
return {
totalAssets: totalAssets,
yearDays: yearDays,
totalReturns: totalReturns,
annualizedReturns: annualizedReturns,
sharpeRatio: sharpeRatio,
volatility: volatility,
maxDrawdown: maxDrawdown,
maxDrawdownTime: maxDrawdownTime,
maxAssetsTime: maxAssetsTime,
maxDrawdownStartTime: maxDrawdownStartTime,
winningRate: winningRate
}
Dengan mengetahui input dan output, maka kita dapat memahami fungsi ini berfungsi untuk apa. Secara ringkasnya, berikan fungsi ini beberapa rekod semula jadi, seperti aritmatika keuntungan. Fungsi ini akan memberi anda hasil untuk menunjukkan prestasi ujian semula.
Di sini, kita akan melihat bagaimana kodnya dikira:
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
}
}
Algoritma secara keseluruhan tidak rumit dan mungkin mempunyai beberapa konsep yang perlu difahami terlebih dahulu.
Perbezaan: Ini boleh difahami sebagai satu set data pendapatan: Satu, dua, tiga, empat, lima sampel, yang purataannya ialah ((1+2+3+4+5) /5) = 3, dan perbezaan adalah purata jumlah jumlah perpaduan kuadrat perbezaan purata setiap data dengan jumlah purata masing-masing adalah: [ ((1-3) ^ 2 + ((2-3) ^ 2 + ((3-3) ^ 2 + ((4-3) ^ 2 + ((5-3) ^ 2) / 5 = 2, perbezaan adalah 2.
Standar buruk: Akar kuasa dua bilangan aritmatika yang mempunyai perbezaan kuadrat, iaitu perbezaan standard.
Perbezaan: Apabila skala dikira ke tahun, kadar turun naik adalah kecacatan standard.
Dengan memahami konsep-konsep ini dan formula pengiraan, bahagian yang berkaitan dengan pengiraan Sharpe dalam fungsi akan menjadi jelas. Rumus Pengiraan Sharp Pengiraan kadar Sharp: (Rata pulangan tahunan China - kadar faedah tanpa risiko) / deviasi standard
Adakah anda belajar?