Beberapa algoritma indikator kinerja strategi sering dibahas oleh anggota kelompok, dan algoritma juga telah diungkapkan dalam dokumen API FMZ. Namun, tidak mudah dimengerti tanpa komentar. Dalam artikel ini, saya akan membawa Anda untuk menganalisis algoritma. Saya percaya bahwa Anda akan memiliki pemahaman yang jelas tentang konsep rasio Sharpe, penarikan maksimum, tingkat pengembalian dan logika perhitungan setelah membaca artikel ini. Kami akan mulai dengan kode sumber, yang ditulis dalam bahasa JavaScript. Sistem backtesting FMZ juga mengadopsi algoritma ini untuk menghasilkan data kinerja backtesting secara otomatis.
function returnAnalyze(totalAssets, profits, ts, te, period, yearDays)
https://www.fmz.com/api#BacktestingSistem Algoritma Sharpe
Karena ini adalah fungsi perhitungan, harus ada input dan output.
totalAssets, profits, ts, te, period, yearDays
TotalAktif Parameter ini adalah total aset awal ketika strategi mulai berjalan.
keuntungan
Parameter ini penting, karena serangkaian indikator kinerja dihitung berdasarkan data asli ini.[[timestamp1, profit1], [timestamp2, profit2], [timestamp3, profit3],..., [timestampN, profitN]]
. Dapat dilihat bahwa fungsi returnAnalyze membutuhkan struktur data yang mencatat urutan kronologis pengembalian setiap saat. Timestamp1 ke timestampN berada dalam urutan kronologis dari jauh ke dekat. Ada nilai keuntungan pada setiap titik waktu. Misalnya, titik waktu ketiga dalam catatan pengembalian adalah [stempel waktu 3, keuntungan3]. Dalam sistem backtesting online FMZ, data array keuntungan disediakan untuk fungsi ini oleh sistem backtesting. Tentu saja, jika Anda merekam data pengembalian sendiri dan membentuk struktur array seperti itu, Anda juga dapat memasoknya ke fungsi perhitungan untuk menghitung hasilnya.
ts Stempel waktu awal dari backtest.
Te Stempel waktu akhir dari backtest.
periode Periode perhitungan pada tingkat milidetik.
Selanjutnya, mari kita lihat output dari fungsi ini bersama-sama:
return {
totalAssets: totalAssets,
yearDays: yearDays,
totalReturns: totalReturns,
annualizedReturns: annualizedReturns,
sharpeRatio: sharpeRatio,
volatility: volatility,
maxDrawdown: maxDrawdown,
maxDrawdownTime: maxDrawdownTime,
maxAssetsTime: maxAssetsTime,
maxDrawdownStartTime: maxDrawdownStartTime,
winningRate: winningRate
}
Mengetahui input dan output, kita dapat memahami apa fungsi yang digunakan untuk. Sederhananya, memberikan fungsi beberapa catatan asli, seperti array statistik kembali. Fungsi akan memberikan hasil untuk menunjukkan kinerja backtest.
Selanjutnya, mari kita lihat bagaimana kode dihitung:
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
}
}
Secara keseluruhan, algoritma tidak rumit, dan mungkin ada beberapa konsep yang perlu dipahami sebelumnya.
Variansi: Hal ini dapat dipahami sebagai satu set data kembali. Kelompok sampel, 1, 2, 3, 4 dan 5, memiliki nilai rata-rata (1+2+3+4+5)/5 = 3, sedangkan varians adalah nilai rata-rata dari jumlah kuadrat perbedaan antara masing-masing data dan jumlahnya masing-masing, yaitu [(1-3) ^ 2 + (2-3) ^ 2 + (3-3) ^ 2 + (4-3) ^ 2 + (5-3) ^ 2) / 5 = 2, dan variansnya adalah 2.
Penyimpangan standar: Hitung akar kuadrat aritmatika dari varians, yang merupakan standar deviasi.
Volatilitas: Ketika skala perhitungan diperpanjang ke tahun, volatilitas adalah standar deviasi.
Dengan pemahaman konsep-konsep ini dan rumus perhitungan, bagian perhitungan Sharpe dari fungsi akan jelas sekilas. Rumus Sharpe untuk menghitung rasio Sharpe: (tingkat pengembalian tahunan - tingkat bebas risiko) / deviasi standar
Apa kau sudah mempelajarinya?