⚙
把指标实现为类:以峰谷指标与 ATR 为例
指标类prev_calculatedATR
为什么把指标做成类
断线或历史同步中断时,prev_calculated 会被清零,触发针对整个历史的重算。影响因素越多(大周期、复杂计算、多品种、机器差),重算代价越大。把指标封装成类、缓存中间结果,是缓解此问题的工程化手段。
prev_calculated 与重算陷阱
⚠ 断线会清零
连接中断或重大历史同步时,prev_calculated 被设为 0,导致整段重算。设计指标时必须能“从任意位置续算”,不能假设总是增量更新。
峰谷指标类
峰谷(ZigZag)指标维护一个极值点序列 ZZBar。类持有 m_prev_calculated 与缓冲,只对新柱计算,避免每 tick 全量重算。
class CCustZigZagPPC
{
int m_prev_calculated;
ZZBar m_bars[]; // 极值点序列
public:
bool Init(void);
int Calculate(const int rates_total, const int prev_calculated);
};
struct ZZBar { double price; int index; int type; };
ATR 类示例
ATR 类封装 iATR 句柄与缓冲,对外暴露 Calc(pos) 增量计算,便于在多个指标间复用。
class CCustATR
{
double m_buf[];
public:
bool Init(void) { /* 建句柄 */ return true; }
bool Calc(int pos)
{
m_buf[pos] = iATR(_Symbol, PERIOD_CURRENT, 14, pos);
return true;
}
};
在 OnCalculate 中调用
主指标把子指标组合进来,统一用 prev_calculated 控制增量区间,既清晰又可复用。
int OnCalculate(const int rates_total,
const int prev_calculated, ...)
{
if(!atr.Calc(rates_total-1)) return 0;
if(!zz.Calculate(rates_total, prev_calculated)) return 0;
return rates_total;
}
小结
✦ 类封装的收益
指标即类让逻辑可复用、可组合、可单元测试,也便于在断线重算时只补算差异部分,显著提升多品种多周期下的性能。
常见问题
断线或历史同步中断时终端会清零,触发整段重算;类缓存可缓解。
类可持有状态、组合多个子指标、避免重复计算,更适合复杂逻辑。
若每个图表实例都重算会慢;类封装+限制计算深度能显著提速。