Dengan algoritma indikator seperti Sharp Rate, Maximum Recoil, Rate of Return dalam analisis strategi Anda

Penulis:Mimpi kecil, Dibuat: 2022-11-26 15:13:17, Diperbarui: 2023-09-18 20:21:39

img

Dengan algoritma indikator seperti Sharp Rate, Maximum Recoil, Rate of Return dalam analisis strategi Anda

Beberapa algoritma indikator kinerja yang sering dibahas oleh teman-teman dalam diskusi strategi, dan juga di publikasikan dalam dokumen API FMZ. Namun, tanpa komentar, ada beberapa hal yang kurang dipahami. Artikel ini akan membawa Anda untuk menganalisis algoritma ini, dan saya yakin setelah membaca artikel ini, Anda harus memiliki pemahaman yang lebih jelas tentang perhitungan konsep dan logika seperti rasio Sharp, mundur maksimum, rasio laba, dan lain-lain.

Kami langsung mengunggah kode sumber, kode yang ditulis dalam bahasa JavaScript. FMZ juga menggunakan algoritma ini untuk menghasilkan data kinerja backtest secara otomatis.

Fungsi returnAnalyze

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

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

Karena ini adalah fungsi perhitungan, maka pasti ada input, output.

totalAssets, profits, ts, te, period, yearDays
  • total aset Parameter ini adalah total aset awal pada saat kebijakan dimulai.

  • keuntungan Parameter ini adalah parameter yang lebih penting karena sejumlah perhitungan indikator kinerja dilakukan di sekitar data mentah ini. Parameter ini adalah suatu aritmatika dua dimensi dengan format misalnya:[[timestamp1, profit1], [timestamp2, profit2], [timestamp3, profit3], ....., [timestampN, profitN]], dapat dilihat bahwa fungsi returnAnalyze ini membutuhkan struktur data yang mencatat urutan waktu keuntungan setiap saat. Timestamp1 ke timestampN adalah urutan waktu dari jauh dan dekat. Pada setiap titik waktu ada nilai keuntungan. Misalnya titik waktu ketiga dalam catatan keuntungan adalah [timestamp3, profit3]. Dalam sistem retargeting online FMZ, kumpulan data keuntungan ini dikembalikan oleh sistem pengujian untuk fungsi ini, tentu saja jika Anda mencatat data keuntungan sendiri, membentuk struktur aritmatika seperti itu, Anda juga dapat memberikan fungsi ini untuk menghitung hasilnya.

  • ts Waktu awal retesting berkumandang.

  • Te Saat akhir tes adalah malam.

  • periode Periode perhitungan pada tingkat milidetik.

  • tahunDays Hari perdagangan dalam setahun.

Sekarang mari kita lihat hasil dari 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
    }
  • totalAssets: Nilai bersih awal
  • yearDays: jumlah hari transaksi
  • totalReturns: tingkat pengembalian yang terkumpul
  • AnnualizedReturns: Pengembalian tahunan
  • SharpeRatio: Rasio Sharpe
  • volatility: tingkat volatilitas
  • maxDrawdown: maksimum penarikan
  • maxDrawdownTime: waktu maksimum untuk mundur
  • maxAssetsTime: waktu saat maksimum nilai bersih
  • maxDrawdownStartTime: Waktu awal maksimum untuk mundur
  • winningRate: tingkat kemenangan

img

Setelah mengetahui input dan output, maka kita sudah tahu fungsi ini digunakan untuk apa. Sederhananya, berikan fungsi ini beberapa catatan asli, seperti hasil statistik. Fungsi ini akan menghitung hasil untuk menunjukkan kinerja retest.

Di sini kita akan melihat bagaimana kode menghitungnya:

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 ada beberapa konsep yang perlu diketahui sebelumnya.

  • Perbedaan: Data ini dapat diartikan sebagai kumpulan data pendapatan: 1, 2, 3, 4, 5, contoh ini, rata-rata adalah ((1+2+3+4+5) /5) = 3, dan perbedaannya adalah rata-rata dari jumlah dari dua pertiga dari perbedaan rata-rata dari jumlah rata-rata masing-masing data, maka: [ ((1-3) ^ 2 + ((2-3) ^ 2 + ((3-3) ^ 2 + ((4-3) ^ 2 + ((5-3) ^ 2) / 5 = 2, perbedaannya adalah 2.

  • Standar buruk: Dengan demikian, kita dapat melihat bahwa nilai-nilai ini tidak sama dengan nilai-nilai lain.

  • Perbedaan: Ketika skala dihitung ke tahun, fluktuasi adalah deviasi standar.

Dengan memahami konsep-konsep ini dan rumus-rumusnya, maka bagian tentang perhitungan Sharpe dalam fungsi akan menjadi jelas. Rumus perhitungan Sharpe: (Rata pengembalian tahunan - suku bunga tanpa risiko) / deviasi standar

Apakah Anda sudah belajar?


Berkaitan

Lebih banyak