Algorithms con indicadores como el Sharp Rate, el máximo retraso, el rendimiento, etc. en su análisis de estrategias de retrospección

El autor:Un sueño pequeño., Creado: 2022-11-26 15:13:17, Actualizado: 2023-09-18 20:21:39

img

Algorithms con indicadores como el Sharp Rate, el máximo retraso, el rendimiento, etc. en su análisis de estrategias de retrospección

A menudo hay amigos que discuten algunas estrategias de algoritmos de indicadores de rendimiento, y también se publicó un algoritmo en el documento API de FMZ. Sin embargo, sin comentarios, hay algunas incomprensiones, este artículo te lleva a analizar este algoritmo, y creo que después de leer este artículo deberías tener una comprensión más clara de los conceptos de cálculo y lógica, como la tasa de Sharpe, el retiro máximo, la rentabilidad y otros.

El código se carga directamente al código fuente, el código está escrito en JavaScript. El sistema de retrospección de FMZ también utiliza este algoritmo para generar datos de rendimiento de retrospección automáticos.

La función returnAnalyze

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

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

Como es una función computacional, entonces tiene que haber una entrada, una salida.

totalAssets, profits, ts, te, period, yearDays
  • Total de activos Este parámetro es el total de activos iniciales cuando la política se inicia.

  • las ganancias Este parámetro es un parámetro importante, ya que una serie de cálculos de indicadores de rendimiento se realizan alrededor de este dato primario.[[timestamp1, profit1], [timestamp2, profit2], [timestamp3, profit3], ....., [timestampN, profitN]]Como se puede ver, la función returnAnalyze requiere una estructura de datos que registre el orden de tiempo en el que se obtienen los beneficios en cada momento. Las secuencias de tiempo desde el timestamp1 hasta el timestampN están en el orden de tiempo desde lejos y cerca. Cada punto de tiempo tiene un valor de ganancia.

  • ¿Qué es esto? El tiempo de inicio de las revisiones es de 2 horas.

  • el El tiempo de finalización de la revisión es de 2 horas.

  • período Los ciclos de cálculo a nivel de milisegundos.

  • añoDays El día de la transacción de un año.

Ahora vamos a ver el resultado de esta función:

return {
        totalAssets: totalAssets,
        yearDays: yearDays,
        totalReturns: totalReturns,
        annualizedReturns: annualizedReturns,
        sharpeRatio: sharpeRatio,
        volatility: volatility,
        maxDrawdown: maxDrawdown,
        maxDrawdownTime: maxDrawdownTime,
        maxAssetsTime: maxAssetsTime,
        maxDrawdownStartTime: maxDrawdownStartTime,
        winningRate: winningRate
    }
  • Total de activos: el valor neto inicial
  • añoDays: número de días de transacción
  • totalReturns: el rendimiento acumulado
  • AnnualizedReturns: Rendimiento anual en China
  • SharpeRatio: el índice de Sharpe
  • Volatilidad: el tipo de volatilidad
  • maxDrawdown: el máximo de retirada
  • maxDrawdownTime: el tiempo máximo de retirada
  • maxAssetsTime: el tiempo de tiempo en el que el valor neto máximo
  • maxDrawdownStartTime: el tiempo máximo de inicio del retroceso
  • winningRate: porcentaje de ganancias

img

Una vez que sabemos cuál es la entrada y la salida, entonces entendemos para qué sirve esta función. En pocas palabras, le damos a esta función algunos registros primitivos, como las estadísticas de ganancia. La función le calcula un resultado para mostrar el rendimiento de la retrospección.

Ahora vamos a ver cómo se calcula el código:

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
    }
}

En general, los algoritmos no son complejos y pueden contener varios conceptos que requieren un conocimiento previo.

  • La diferencia: Se puede entender como un conjunto de datos de ganancias: La muestra de 1, 2, 3, 4, 5 tiene un promedio de 1 + 2 + 3 + 4 + 5 / 5 = 3 y la diferencia es el promedio de la suma de los cuadrados de la diferencia entre el promedio de cada dato y su suma.

  • Los estándares bajos: La raíz cuadrada de la diferencia de cuadrados, es decir, el diferencial estándar.

  • La velocidad de fluctuación: Cuando la escala se calcula en años, la variación es el desvío estándar.

Con estos conceptos y las fórmulas de cálculo, la parte de la función sobre el cálculo de Sharpe también está clara. La fórmula de cálculo de Sharpe para calcular la tasa de Sharpe: (Rentabilidad anual de China - tasa de interés sin riesgo) / Desviación estándar

¿Se lo han aprendido?


Relacionados

Más.