动态策略分析工具

Author: ChaoZhang, Date: 2023-10-13 15:54:35
Tags:

概述

这个策略的主要思想是实时模拟交易,收集每周的交易数据,并以表格的形式展示统计结果,以便更直观地查看策略的表现。它可以帮助我们快速评估策略的盈亏情况,找出策略表现不佳的时间段,据此进行策略调整和优化。

策略原理

  1. 设置计算周期的开始和结束时间。

  2. 设置统计结果的精确度和每组包含的周数。

  3. 模拟RSI策略进行买入卖出。

  4. 定义统计表中的变量。

  5. 计算当前周期的结果。

  6. 如果周期改变并且允许交易,记录这一周期的时间和结果。

  7. 如果是最后一根K线且允许交易,记录当前周期的时间和结果。

  8. 如果周期改变且不允许交易,记录上一周期的时间和结果。

  9. 寻找最高和最低的周期结果。

  10. 渲染统计表格。

  • 首先计算统计周期的总数

  • 遍历每一个周期,渲染表头、时间和结果

  • 对每组周期结果进行累积

  • 用颜色标记正负结果

优势分析

  • 可以实时观察每周交易结果,快速评估策略表现

  • 直观展示结果,一目了然,便于找出策略表现差的周期

  • 可以根据时间段的盈亏情况,调整和优化策略参数

  • 可以方便地跟踪长期持仓策略的多周累积收益

  • 可以对不同时间段的交易风格进行对比分析

  • 自定义统计精度和分组周数,满足不同需求

  • 代码实现简单清晰,容易理解和二次开发

风险分析

  • 本策略基于RSI进行模拟交易,RSI策略本身存在跟随趋势不够强的缺点

  • 在实盘中,交易费用会对结果产生较大影响

  • 用于回测的历史数据不一定能反映实际交易环境

  • 统计结果依赖真实账户资金数额,回测中默认资金数额不一定准确

  • 需要注意防止过拟合,根据回测结果盲目修改策略参数

可以通过结合更多指标判断趋势,优化入场退出点,来增强RSI策略。实盘交易时注意按真实参数设置手续费。在回测阶段增大资金数额的波动,使之更贴近实际情况等。要持怀疑态度,避免根据统计结果过度调整策略。

优化方向

  • 可以考虑加入止损逻辑,控制单笔损失

  • 可以优化策略参数,如调整RSI的看涨看跌阈值

  • 可以尝试不同的交易频率,例如日内交易或月度持仓

  • 可以加入更多指标判断市场趋势和入场时机

  • 可以考虑加入止盈逻辑

  • 可以优化统计参数的设置

  • 可以考虑实现对多种资产的统计

通过加入止损止盈,可以更好控制风险和收益比。优化RSI参数可以提高获胜率。采用更多指标和不同交易频率可以使策略更稳定。调整统计参数可以使结果更突出重点。从单一资产扩展到多资产统计,可以全面判断策略效果。

总结

该策略的目的是收集周期交易结果,以统计表格的形式直观展示,可以快速判断策略在不同时间段的盈亏情况。这为策略优化提供了数据支持。优点是可以实时查看每周结果,直观清晰,易于二次开发。需要注意的是,统计结果可能会导致过度依赖和拟合回测数据。我们应保持理性,结合策略本身的原理进行综合判断,用统计结果来发现问题而不是直接作为修改的依据。总体来说,该策略为快速评估策略表现提供了便利,在策略优化中发挥着重要作用。


/*backtest
start: 2023-09-12 00:00:00
end: 2023-10-12 00:00:00
period: 3h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

//@version=5
// strategy('Strategy weekly results as numbers v1', overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=25, commission_type=strategy.commission.percent, commission_value=0.04)

after = input(title='Trade after', defval=timestamp('01 Jan 2019 00:00 UTC'), tooltip="Strategy will be executed after this timestamp. The statistic table will include only periods after this date.")
before = input(title='Trade before', defval=timestamp('31 Dec 2024 23:59 UTC'), tooltip="Strategy will be executes before this timestamp. The statistic table will include only periods before this date.")

statisticPrecision = input.int(title='Statistic precision', group='Statistic visualisation', defval=1, tooltip="Defines how many digits should be rendered in every statistic cell.")
statisticGroupSize = input.int(title='Statistic group size', group='Statistic visualisation', defval=12, tooltip="Defines how many cells should be in one group inside the statistic table.")

// determinet whether the starategy should be traded between the period
isTradeEnabled = true


// *******************************************************************************************
// Core strategy simulation logic
// *******************************************************************************************
// calculate rsi strategy emulation data
rsiEmulationData = ta.rsi(close, 7)
rsiEmulationCrossover = ta.crossover(rsiEmulationData, 70)
rsiEmulationCrossunder = ta.crossunder(rsiEmulationData, 30)

// entry loogic based on the rsi calculations
if (isTradeEnabled and rsiEmulationCrossover)
    strategy.entry('Long', strategy.long)
if (isTradeEnabled and rsiEmulationCrossunder)
    strategy.entry('Short', strategy.short)


// *******************************************************************************************
// Weekly statistics table
// *******************************************************************************************
// define statistic variables
var statisticTable = table(na)
var statisticPeriodTime = array.new_int(0)
var statisticPeriodResult = array.new_float(0)
var statisticIsLatestCalculated = bool(na)
var statisticResultHighest = float(na)
var statisticResultLowest = float(na)
var statisticColorGray = color.new(color.gray, transp = 60)
var statisticColorGreen = color.new(color.green, transp = 60)
var statisticColorRed = color.new(color.red, transp = 60)

// claculate current period result
barResult = not na(strategy.equity[1])
             ? (strategy.equity / strategy.equity[1] - 1) : 0
isPeriodChanged = not na(time[1]) and weekofyear(time) != weekofyear(time[1])
currentPeriodResult = 0.0
currentPeriodResult := not na(currentPeriodResult[1]) and not isPeriodChanged
                       ? ((1 + currentPeriodResult[1]) * (1 + barResult) - 1) : 0.0

// initialise highest and lowest results variables
statisticResultHighest := na(statisticResultHighest) ? currentPeriodResult : statisticResultHighest
statisticResultLowest := na(statisticResultLowest) ? currentPeriodResult : statisticResultLowest

// search for highest and lowest results
statisticResultHighest := currentPeriodResult > statisticResultHighest ? currentPeriodResult : statisticResultHighest
statisticResultLowest := currentPeriodResult < statisticResultLowest ? currentPeriodResult : statisticResultLowest

// new week while trade is active
if isPeriodChanged and isTradeEnabled
    timeCalculated = time - 1000 * 60 * 60 * 24 * 7
    resultCalculated = currentPeriodResult[1]
    statisticIsLatestCalculated := false

    array.push(statisticPeriodTime, timeCalculated)
    array.push(statisticPeriodResult, resultCalculated)

// latest bar while trade is active
if barstate.islast and isTradeEnabled
    timeCalculated = time - 1000 * 60 * 60 * 24 * (dayofweek(time) - 2)
    resultCalculated = currentPeriodResult

    array.push(statisticPeriodTime, timeCalculated)
    array.push(statisticPeriodResult, resultCalculated)

// new week after trade disabled
if isPeriodChanged and not isTradeEnabled and not na(statisticIsLatestCalculated) and not statisticIsLatestCalculated
    timeCalculated = time - 1000 * 60 * 60 * 24 * (dayofweek(time) + 5)
    resultCalculated = currentPeriodResult[1]
    statisticIsLatestCalculated := true

    array.push(statisticPeriodTime, timeCalculated)
    array.push(statisticPeriodResult, resultCalculated)

// render statistics table
if barstate.islast
    statisticLength = array.size(statisticPeriodResult)
    statisticTableSteps = math.floor(statisticLength / statisticGroupSize) + (statisticLength % statisticGroupSize != 0 ? 1 : 0)
    statisticTable := table.new(position.bottom_right, columns = statisticGroupSize + 2, rows = statisticTableSteps + 1, border_width = 1)

    // render headers
    for i = 0 to (statisticGroupSize - 1)
        statisticHeaderContent = str.tostring(i + 1)
        table.cell(statisticTable, 1 + i, 0, statisticHeaderContent, bgcolor = statisticColorGray)

    // render time points
    for i = 0 to (statisticTableSteps - 1)
        statisticPointContent = str.format("{0,date,medium}", array.get(statisticPeriodTime, i * statisticGroupSize))
        table.cell(statisticTable, 0, 1 + i, statisticPointContent, bgcolor = statisticColorGray)

    // render the result
    statisticResultCummulative = 0.0
    for i = 0 to (array.size(statisticPeriodTime) - 1)
        statisticColumn = 1 + i % statisticGroupSize
        statisticRow = 1 + math.floor(i / statisticGroupSize)

        statisticResult = array.get(statisticPeriodResult, i)
        statisticResultCummulative := (i % statisticGroupSize == 0) ? 0.0 : statisticResultCummulative
        statisticResultCummulative := (1 + statisticResultCummulative) * (1 + statisticResult) - 1

        statisticResultColor = statisticResult > 0 ? statisticColorGreen : statisticColorRed
        table.cell(statisticTable, statisticColumn, statisticRow, str.tostring(math.round(statisticResult * 100, statisticPrecision)), bgcolor = statisticResultColor)

        // if it is the last item of the row or data array
        isStatisticLastOfTheRow = ((i + 1) % statisticGroupSize) == 0
        isStatisticLastOfTheData = i == (statisticLength - 1)
        if (isStatisticLastOfTheRow or isStatisticLastOfTheData)
            resultsTableCummulativeCellColor = statisticResultCummulative > 0 ? statisticColorGreen : statisticColorRed
            resultsTableCummulativeCellContent = str.tostring(math.round(statisticResultCummulative * 100, statisticPrecision))
            table.cell(statisticTable, 1 + statisticGroupSize, statisticRow, resultsTableCummulativeCellContent, bgcolor = resultsTableCummulativeCellColor)

更多内容