Возьмите вас, чтобы проанализировать коэффициент Шарпа, максимальное снижение, уровень доходности и другие алгоритмы индикатора в стратегии backtesting

Автор:Лидия., Создано: 2022-11-28 16:44:25, Обновлено: 2023-09-13 19:42:38

img

Возьмите вас, чтобы проанализировать коэффициент Шарпа, максимальное снижение, уровень доходности и другие алгоритмы индикатора в стратегии backtesting

Некоторые алгоритмы показателей эффективности стратегии часто обсуждаются членами группы, и алгоритм также был раскрыт в API-документе FMZ. Однако его нелегко понять без комментариев. В этой статье я приведу вас к анализу алгоритма. Я считаю, что после прочтения этой статьи вы получите четкое понимание концепций коэффициента Шарпа, максимального снижения, показателя возврата и логики расчета. Мы начнем с исходного кода, который написан на языке JavaScript. Система бэкстестинга FMZ также использует этот алгоритм для автоматической генерации данных о производительности бэкстестинга.

returnФункция анализа

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

https://www.fmz.com/api#BacktestingСистема алгоритм Шарпа

Поскольку это вычислительная функция, должны быть входы и выходы.

totalAssets, profits, ts, te, period, yearDays
  • Совокупность активов Данный параметр представляет собой начальные общие активы при запуске стратегии.

  • прибыль Этот параметр является важным, поскольку на основе этих исходных данных рассчитывается ряд показателей производительности.[[timestamp1, profit1], [timestamp2, profit2], [timestamp3, profit3],..., [timestampN, profitN]]. Можно увидеть, что функция returnAnalyze нуждается в такой структуре данных, которая записывает хронологический порядок возвратов в каждое время. Временные знаки от 1 до N расположены в хронологическом порядке от дальнего до близкого. В каждом момент времени есть значение прибыли. Например, третий временной момент в записи возвратов является [временная марка 3, прибыль3]. В онлайн-системе обратного тестирования FMZ данные массива прибыли предоставляются этой функции системой обратного тестирования. Конечно, если вы записываете данные возврата сами и формируете такую структуру массива, вы также можете предоставить его функции расчета для расчета результатов.

  • Тс Время начала обратного теста.

  • Тэ Время окончания теста.

Период Период расчета на уровне миллисекунд.

  • годДни Торговые дни за год.

Далее, давайте посмотрим на выход этой функции вместе:

return {
        totalAssets: totalAssets,
        yearDays: yearDays,
        totalReturns: totalReturns,
        annualizedReturns: annualizedReturns,
        sharpeRatio: sharpeRatio,
        volatility: volatility,
        maxDrawdown: maxDrawdown,
        maxDrawdownTime: maxDrawdownTime,
        maxAssetsTime: maxAssetsTime,
        maxDrawdownStartTime: maxDrawdownStartTime,
        winningRate: winningRate
    }
  • Общий актив: общий актив
  • ГодДни: дни торговли
  • Общий доход: общий доход
  • годовые доходы: годовые доходы
  • SharpeRatio: Соотношение Sharpe
  • волатильность: волатильность
  • maxDrawdown: максимальное извлечение
  • maxDrawdownTime: временная отметка при максимальном выводе
  • maxAssetsTime: временная отметка при максимальных активах
  • maxDrawdownStartTime: время начала максимального сбора средств
  • WinningRate: выигрышный процент

Зная вход и выход, мы можем понять, для чего используется функция. Проще говоря, она дает функции некоторые оригинальные записи, такие как массив статистики возврата. Функция даст вам результат, чтобы показать производительность обратного теста.

Далее, давайте посмотрим, как вычисляется код:

function returnAnalyze(totalAssets, profits, ts, te, period, yearDays) {
    // force by days
    period = 86400000                  // The number of milliseconds in a day, that is 60 * 60 * 24 * 1000
    if (profits.length == 0) {         // If the length of the array of profits is 0, it cannot be calculated and it will return to the null value directly
        return null
    }
    var freeProfit = 0.03              // Risk-free interest rate, which can also be set according to the demand, such as 3% annualized national debt
    var yearRange = yearDays * 86400000          // Milliseconds of all accumulated trading days in a year
    var totalReturns = profits[profits.length - 1][1] / totalAssets      // Total return rate
    var annualizedReturns = (totalReturns * yearRange) / (te - ts)       // The annualized rate of return, the expected rate of return obtained by scaling the time of profit statistics to the scale of one year

    // MaxDrawDown
    var maxDrawdown = 0           // Initialize the maximum drawdown variable to 0
    var maxAssets = totalAssets   // Initialize maximum asset variable with initial net value assignment
    var maxAssetsTime = 0         // Timestamp of the time when the maximum asset is initialized
    var maxDrawdownTime = 0       // Timestamp of the time when the maximum drawdown is initialized
    var maxDrawdownStartTime = 0  // Timestamp of the time when the maximum start time is initialized
    var winningRate = 0           // Initialized win rate is 0
    var winningResult = 0         // Record the number of win time
    for (var i = 0; i < profits.length; i++) {      // Traverse the return array
        if (i == 0) {
            if (profits[i][1] > 0) {                // If the first return record point, the return is greater than 0, it means the profit
                winningResult++                     // The number of win times accumulates 1 
            }
        } else {                                    // If it is not the first returns record point, as long as the returns of the current point is greater than the returns of the previous moment (return point), it means profit, and the number of win times accumulates 1 
            if (profits[i][1] > profits[i - 1][1]) {
                winningResult++
            }
        }
        if ((profits[i][1] + totalAssets) > maxAssets) {    // If the return plus the initial net value at that moment is greater than the largest asset recorded to have occurred, the value of the largest asset is updated and the timestamp of this moment is recorded
            maxAssets = profits[i][1] + totalAssets
            maxAssetsTime = profits[i][0]
        }
        if (maxAssets > 0) {                                // When the maximum asset value recorded is greater than 0, the drawdown is calculated
            var drawDown = 1 - (profits[i][1] + totalAssets) / maxAssets
            if (drawDown > maxDrawdown) {                   // If the current drawdown is greater than the recorded maximum drawdown, update the maximum drawdown, maximum drawdown time, etc
                maxDrawdown = drawDown
                maxDrawdownTime = profits[i][0]
                maxDrawdownStartTime = maxAssetsTime
            }
        }
    }
    if (profits.length > 0) {                            // Calculate the winning rate
        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     // Process rangeEnd as an integer multiple of 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) {    // Ensure that when the timestamp is not out of bounds, the array length is also not out of bounds
            dayProfit += (profits[i][1] - preProfit)           // Calculate the daily returns
            preProfit = profits[i][1]                          // Record yesterday's returns
            i++                                                // Accumulate i for accessing the next profits node
        }
        perRatio = ((dayProfit / totalAssets) * yearRange) / period   // Calculate the annualized rate of return at that time
        sum += perRatio                                               // Accumulation
        datas.push(perRatio)                                          // Put in the array datas
    }

    var sharpeRatio = 0                    // Initial Sharpe ratio is 0
    var volatility = 0                     // Initial volatility is 0
    if (datas.length > 0) {
        var avg = sum / datas.length;      // Find the mean value
        var std = 0;
        for (i = 0; i < datas.length; i++) {
            std += Math.pow(datas[i] - avg, 2);      // The std is used to calculate the following variance. The following std/datas.length is the variance, and the square root of the number is the standard deviation
        }
        volatility = Math.sqrt(std / datas.length);  // In terms of years, volatility is the standard deviation
        if (volatility !== 0) {
            sharpeRatio = (annualizedReturns - freeProfit) / volatility   // Sharpe formula to calculate Sharpe ratio: (annualized return rate - risk-free rate) / standard deviation
        }
    }

    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.

  • Стандартное отклонение: Вычислите арифметический квадратный корень варианса, который является стандартным отклонением.

  • Волатильность: При годовом исчислении шкалы волатильность является стандартным отклонением.

С пониманием этих понятий и расчетных формул, Sharpe расчетная часть функции будет ясно на первый взгляд. Формула Шарпа для расчета коэффициента Шарпа: (годовая ставка доходности - безрисковая ставка) / стандартное отклонение

Ты уже научился?


Больше