导读:本期聚焦于向日葵创作的《iOS如何用Core Graphics绘制股票K线图DMA平行线差指标?计算方法与买卖信号详解》,敬请观看详情。DMA平行线差指标是股票技术分析中常用的趋势判断工具,它通过计算短期移动平均线与长期移动平均线之间的差值,再对差值求平均得到AMA线,利用两条线的交叉关系判断买卖时机。本文将详细讲解DMA指标的计算公式与参数含义,分析DDD线与AMA线的金叉死叉信号原理,并结合iOS开发中的Core Graphics框架,从数据准备、坐标映射到Quartz 2D绘图API的使用,一步步实现一个支持DMA指标的K线图组件,帮助开发者在自建行情页面中还原专业看盘软件的指标效果。

DMA(Different of Moving Average,平行线差指标)是经典的趋势型技术指标,它回避了单一均线系统的滞后问题,通过两条不同周期移动平均线的差值构建出一个独立的震荡体系。在自建股票行情App时,DMA经常和MACD、KDJ一起出现在副图区域。本文将从指标原理、公式推导讲起,再完整演示如何用Core Graphics在iOS端绘制一个带DMA指标的K线图副图。

iOS如何用Core Graphics绘制股票K线图DMA平行线差指标?计算方法与买卖信号详解

DMA平行线差指标的计算原理与公式推导

DMA的核心思想很简单:股价短期波动与长期趋势之间的偏离程度,往往能提前反映趋势的转折。短期均线代表近期成本,长期均线代表总体成本,两者差值放大说明短期资金推动明显,差值收敛甚至转负则说明动能衰竭。

标准DMA指标由两条线组成。第一条是DDD线(有些软件直接叫DMA线),等于短期均线减去长期均线;第二条是AMA线,即对DDD再做一次移动平均,起到平滑滤噪的作用。公式为:

// DMA指标计算公式
DDD = MA(close, N1) - MA(close, N2)     // 常用参数 N1=10, N2=50
AMA = MA(DDD, M)                         // 常用参数 M=10
// 信号判断
// DDD上穿AMA  => 金叉,买入信号
// DDD下穿AMA  => 死叉,卖出信号

举个具体例子更容易理解。假设某股票近10日收盘价的算术平均是12.5元,近50日平均是11.8元,那么当日DDD就是0.7元,表示短期成本高出长期成本7个点左右的溢价。如果连续多日DDD持续放大,说明上涨趋势正在加速;反之DDD从高位回落并向零轴靠拢,通常是趋势转弱的预警。

参数选择上,主流软件默认采用10、50、10的组合。短线交易者可以把N1缩短到5天以提高灵敏度,但代价是信号噪音增多、假交叉频发。需要注意的是,国内股市软件(如通达信)有时采用SMA加权平滑而非简单算术平均,计算结果会和国际默认参数略有出入,开发时建议以自己产品定义的口径为准,并在文档中注明。

iOS端DMA数据计算与K线数据的组织

绘图之前先解决数据层。K线图需要每根K线的开高低收四个价格,DMA计算只需要收盘价序列。建议定义一个蜡烛模型和一个指标模型,把行情数据与指标数据解耦,这样后续扩展MACD等其他指标时不需要改动K线模型。

// K线与DMA数据模型
@interface Candle : NSObject
@property (nonatomic, assign) CGFloat open;
@property (nonatomic, assign) CGFloat high;
@property (nonatomic, assign) CGFloat low;
@property (nonatomic, assign) CGFloat close;
@end

@interface DMAData : NSObject
@property (nonatomic, assign) CGFloat ddd;   // 短期均线与长期均线的差
@property (nonatomic, assign) CGFloat ama;   // DDD的移动平均
@end

// 简单算术移动平均
+ (NSArray<NSNumber *> *)maWithCloses:(NSArray<NSNumber *> *)closes period:(NSInteger)period {
    NSMutableArray *result = [NSMutableArray array];
    for (NSInteger i = 0; i < closes.count; i++) {
        if (i < period - 1) {
            [result addObject:[NSNull null]];  // 数据不足,填充空值
            continue;
        }
        CGFloat sum = 0;
        for (NSInteger j = i - period + 1; j <= i; j++) {
            sum += closes[j].doubleValue;
        }
        [result addObject:@(sum / period)];
    }
    return result;
}

有了通用均线函数后,DMA的计算就是两次调用:先分别求N1周期和N2周期的均线数组,逐点相减得到DDD序列,再对DDD序列求M周期平均得到AMA。注意数据不足的头部点位要用空值占位,绘图时跳过,否则曲线会从错误的位置起笔画出一段塌陷。

// 计算DMA序列
+ (NSArray<DMAData *> *)dmaWithCloses:(NSArray<NSNumber *> *)closes {
    NSArray *shortMA = [self maWithCloses:closes period:10];
    NSArray *longMA  = [self maWithCloses:closes period:50];
    // 先得到DDD序列
    NSMutableArray *dddArr = [NSMutableArray array];
    for (NSInteger i = 0; i < closes.count; i++) {
        if (i < 49 || shortMA[i] == [NSNull null]) {
            [dddArr addObject:[NSNull null]];
        } else {
            CGFloat d = [shortMA[i] floatValue] - [longMA[i] floatValue];
            [dddArr addObject:@(d)];
        }
    }
    // 对DDD求M周期均线得到AMA,逻辑类似,此处省略
    // 最终组装DMAData数组返回
    return result;
}

数据层还要处理增量更新。真实行情是逐笔推送的,最新一根K线会不断变化,重算全部历史显然浪费。合理的做法是缓存历史均线的前缀和,新数据到来时只更新最后一根K线对应的DDD与AMA,滑动到新的一天才追加一个点。这一点在分时图、日线图切换频繁的场景下对性能影响很大。

用Core Graphics绘制K线主图与DMA副图

Core Graphics的核心API是CGContextRef,绘制一般在UIView的drawRect方法内完成。整体布局上,建议把主图(K线加均线)和副图(DMA)拆成两个视图或者用两个绘制区域,中间留出间隔,各自独立计算Y轴刻度,避免副图的负值把主图价格区间压扁。

绘图流程分为四步:第一,根据可见K线的最高价最低价确定主图Y轴范围,根据DDD、AMA的最大最小值确定副图范围,注意副图范围要对称包含零轴;第二,把价格值映射为屏幕坐标,CGContext的Y轴向下为正,所以映射时要翻转;第三,画网格与零轴线;第四,逐根绘制蜡烛和两条指标线。

// 副图绘制核心代码(drawRect内)
- (void)drawRect:(CGRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    // 1. 计算副图数值范围,保证包含零轴
    CGFloat maxV = 0, minV = 0;
    for (DMAData *d in self.visibleDMA) {
        maxV = MAX(maxV, MAX(d.ddd, d.ama));
        minV = MIN(minV, MIN(d.ddd, d.ama));
    }
    CGFloat padding = (maxV - minV) * 0.1;
    maxV += padding; minV -= padding;

    // 2. 值到Y坐标的映射(flipRect为副图绘制区域)
    CGFloat (^yFor)(CGFloat) = ^CGFloat(CGFloat v) {
        return flipRect.origin.y + flipRect.size.height
               * (1 - (v - minV) / (maxV - minV));
    };

    // 3. 画零轴虚线
    CGContextSetStrokeColorWithColor(ctx, [UIColor grayColor].CGColor);
    CGFloat dash[] = {2, 2};
    CGContextSetLineDash(ctx, 0, dash, 2);
    CGContextMoveToPoint(ctx, flipRect.origin.x, yFor(0));
    CGContextAddLineToPoint(ctx, flipRect.origin.x + flipRect.size.width, yFor(0));
    CGContextStrokePath(ctx);
    CGContextSetLineDash(ctx, 0, NULL, 0);

    // 4. 用ADD模式绘制DDD与AMA两条曲线
    [self strokeLineWithContext:ctx values:dddValues
                          color:[UIColor systemOrangeColor] yFor:yFor];
    [self strokeLineWithContext:ctx values:amaValues
                          color:[UIColor systemBlueColor] yFor:yFor];
}

绘制连续曲线时不要每段单独stroke,把所有点用CGContextAddLineToPoint加入同一条路径后一次提交,性能会明显更好。蜡烛体的绘制则要先填充实体再描边影线,阳线阴线用不同颜色区分。如果需要叠加交易信号,可以在金叉死叉的位置画一个小箭头标记,判断逻辑就是相邻两个采样点DDD与AMA的差值符号发生翻转。

交叉信号解读与绘制细节优化

DMA的实战用法主要看三点:金叉死叉、零轴位置、与股价的背离。DDD上穿AMA且两者位于零轴上方,属于强势回调结束的买点;DDD在零轴下方上穿AMA,只能算弱反弹信号,需要结合成交量确认。DDD下穿AMA无论在什么位置都应警惕,若同时伴随股价创新高而DDD走低,就是典型的顶背离,趋势反转概率较大。

绘图细节上,建议在副图顶部显示当前DDD、AMA的实时数值和参数说明,例如“DMA(10,50,10) DDD:0.72 AMA:0.58”,数值颜色与曲线一致,方便用户对照。触控交互方面,可以在副图区域加长按手势,根据触摸点的X坐标反推索引,绘制一条十字光标并刷新数值标签,这是自绘图表区别于第三方库的常见体验点。

性能方面,当K线数量达到几千根时,应只绘制屏幕可见区间的数据,配合CADisplayLink或重绘节流避免高频回调导致的重复绘制。所有颜色、线宽等参数建议收敛到一个样式对象统一管理,方便后续做夜间模式切换。至此,一个完整支持DMA平行线差指标的iOS K线图组件就具备了数据、计算、绘制、交互四个层面的完整闭环,可以在此基础上继续扩展MACD、RSI等其他副图指标。

Core GraphicsDMA指标K线图修改时间:2026-09-15 10:20:49

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260915/57209.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。