�?返回首页

从零入门期货程序化:�?�?- 第一个交易策略:从思路到代码,程序下第一笔单

�?集:第一个交易策略——从思路到代码,让程序下第一笔单


上一�?/a>你的程序长了眼睛——能看见行情了�?/p>

但光看见有什么用?你站在路边看别人开车,自己连方向盘都没摸过�?/p>

这一集,你坐上驾驶座。踩油门。挂挡。让程序替你下第一笔单�?/p>

别怕。我会一步一步带你走。你只需要跟着做,每一步都有代码,每一步都有解释�?/p>


一、策略是什么?先想清楚再写代码

很多人一上来就写代码,写着写着发现逻辑不对,删了重来,又不对,又删。折腾半天,代码乱成一团�?/p>

问题不在代码。问题在你没想清楚策略到底是什�?/strong>�?/p>

写策略之前,先回答这五个问题�?/p>

问题你的答案
做什么品种?螺纹钢(rb�?/td>
什么时候买�?/strong>价格突破昨天最高价
买多少?1�?/td>
什么时候卖�?/strong>盈利50个点,或亏损30个点
什么时候不买?昨天是阴线(收盘价低于开盘价)就不做

这五个问题就是你的策略。代码只是把这五个答案翻译成程序语言�?/p>

你看,策略一点都不神秘。它就是一组规则:什么条件触发什么动作�?/p>

今天我们写的策略�?strong>"突破策略"——价格突破昨天高点就买入,盈�?0点止盈,亏损30点止损。简单、清晰、适合入门�?/p>


二、策略的骨架——四个核心函�?/h2>

一个完整的策略程序,有四个核心函数,就像一辆车有四个轮子:

on_tick()   �?看行情(眼睛�?on_bar()    �?看K线(大脑�?on_trade()  �?确认成交(耳朵�?on_order()  �?确认委托状态(仪表盘)

它们的关系是这样的:

行情进来 �?on_tick() 每秒触发几百�?          �?on_bar() 每分钟合成一根K�?          �?策略逻辑�?on_bar() 里判�?          �?条件满足 �?发出买入指令
          �?on_trade() 确认成交
          �?持仓�?�?等止�?止损条件
          �?条件满足 �?发出卖出指令

为什么策略逻辑放在 on_bar() 而不�?on_tick()�?/strong>

因为tick太碎了。螺纹钢一秒钟可能有几十笔tick,你如果在tick里做判断,一秒钟判断几十次,大部分是噪音�?/p>

K线是"压缩后的行情"。一�?分钟K线把60秒的所有tick压缩成四个数字:开盘价、最高价、最低价、收盘价。你只需要看这四个数字,就能判断"这根K线发生了什�?�?/p>

就像你看天气预报,不需要每秒看温度计,�?今天最高温32�?就够了�?/p>


三、完整策略代码——突破策�?/h2>

创建文件 breakout_strategy.py,把下面的代码复制进去:

import time
from ctpbee import CtpBee
from ctpbee.constant import TickData, BarData, TradeData, OrderData
from ctpbee.constant import Direction, Offset, Exchange, OrderType

============ 账户配置 ============

BROKER_ID = "9999" USER_ID = "你的SimNow账号" PASSWORD = "你的密码" TD_ADDRESS = "tcp://180.168.146.187:10130" MD_ADDRESS = "tcp://180.168.146.187:10131"

============ 策略参数 ============

SYMBOL = "rb2510" # 合约代码(改成当前主力合约) EXCHANGE = Exchange.SHFE # 上期所 LOTS = 1 # 每次�?�?PROFIT_TARGET = 50 # 止盈�?0个点 STOP_LOSS = 30 # 止损�?0个点

============ 策略状�?============

yesterday_high = None # 昨天最高价 yesterday_close = None # 昨天收盘�?yesterday_open = None # 昨天开盘价 position = 0 # 当前持仓�?=空仓�?=持多�?entry_price = 0 # 入场价格 today_traded = False # 今天是否已经交易�?

====================================

创建应用

====================================

app = CtpBee("breakout", "strategy") config = { "CONNECT_INFO": { "brokerid": BROKER_ID, "userid": USER_ID, "password": PASSWORD, "td_address": TD_ADDRESS, "md_address": MD_ADDRESS, }, "SUBSCRIBE_INFO": [SYMBOL] # 订阅行情 } app.config.from_mapping(config)

====================================

策略逻辑

====================================

@app.route(handler="on_bar") def on_bar(bar): """ 每分钟收到一根K线时触发�? 策略的核心判断在这里�? """ global yesterday_high, yesterday_close, yesterday_open global position, entry_price, today_traded # ---- 第一步:记录昨天的高�?---- # 每根K线都有日期。如果日期变了,说明新的一天开始了�? # 我们用新一天的第一根K线来"锁定"昨天的数据�? # (简化处理:实际项目中应该用日线数据�? # ---- 第二步:判断买入条件 ---- # 条件1:今天还没交易过(一天只做一次) # 条件2:昨天是阳线(收�?> 开盘),说明昨天上涨了 # 条件3:当前价格突破了昨天最高价 if not today_traded and yesterday_high is not None: # 昨天是阳线? is_yang_line = yesterday_close > yesterday_open # 当前K线的最高价突破了昨天高点? if is_yang_line and bar.high_price > yesterday_high: print(f"🚀 突破信号!当前最高价 {bar.high_price} > 昨天高点 {yesterday_high}") print(f" 昨天是阳线:开�?{yesterday_open},收�?{yesterday_close}") # 发出买入指令 app.buy( symbol=SYMBOL, exchange=EXCHANGE, price=bar.close_price, # 用当前收盘价下单 volume=LOTS, order_type=OrderType.LIMIT # 限价�? ) today_traded = True print(f" 📤 已发出买入指令:{SYMBOL} {LOTS}�?@ {bar.close_price}") # ---- 第三步:判断止盈/止损 ---- if position > 0: # 如果持有多头仓位 profit = bar.close_price - entry_price # 盈亏点数 if profit >= PROFIT_TARGET: print(f"💰 止盈触发!盈�?{profit} �?>= 目标 {PROFIT_TARGET} �?) app.sell( symbol=SYMBOL, exchange=EXCHANGE, price=bar.close_price, volume=LOTS, order_type=OrderType.LIMIT ) print(f" 📤 已发出卖出指令(止盈�?) elif profit <= -STOP_LOSS: print(f"🛑 止损触发!亏�?{profit} �?<= 容忍 {-STOP_LOSS} �?) app.sell( symbol=SYMBOL, exchange=EXCHANGE, price=bar.close_price, volume=LOTS, order_type=OrderType.LIMIT ) print(f" 📤 已发出卖出指令(止损�?) @app.route(handler="on_tick") def on_tick(tick): """ 收到行情时触发。这里我们只用来更新昨天的高点数据�? (简化版:用tick的最高价来模拟昨天的最高价�? """ global yesterday_high, yesterday_close, yesterday_open # 在实际项目中,你应该用日线数据来获取昨天的高点�? # 这里简化处理:用最近看到的最高价作为参考�? # 后面回测章节会教你用正确的方式获取历史数据�? if yesterday_high is None or tick.last_price > yesterday_high: yesterday_high = tick.last_price if yesterday_close is None: yesterday_close = tick.last_price if yesterday_open is None: yesterday_open = tick.last_price @app.route(handler="on_trade") def on_trade(trade): """ 成交回报。当你的订单真正成交时触发�? """ global position, entry_price if trade.direction == Direction.LONG: # 买入成交 position += trade.volume entry_price = trade.price print(f"�?买入成交!价�?{trade.price},数�?{trade.volume}�?) print(f" 当前持仓:{position}手,入场价:{entry_price}") elif trade.direction == Direction.SHORT: # 卖出成交 position -= trade.volume print(f"�?卖出成交!价�?{trade.price},数�?{trade.volume}�?) print(f" 当前持仓:{position}�?) @app.route(handler="on_order") def on_order(order): """ 委托状态回报。你的订单被交易所受理、排队、成交、或拒绝时触发�? """ print(f"📋 委托状态更新:{order.status} | {order.symbol} | {order.direction}")

====================================

启动

====================================

if __name__ == "__main__": print("=" * 60) print("🚀 突破策略启动") print(f" 品种:{SYMBOL}") print(f" 止盈:{PROFIT_TARGET} �?) print(f" 止损:{STOP_LOSS} �?) print(f" 手数:{LOTS}") print("=" * 60) app.start() try: while True: time.sleep(1) except KeyboardInterrupt: print("\n🛑 程序停止") app.release()


四、逐段拆解——你写的每一行都在干什�?/h2>

策略参数�?/h3>
SYMBOL = "rb2510"
EXCHANGE = Exchange.SHFE
LOTS = 1
PROFIT_TARGET = 50
STOP_LOSS = 30

这五行定义了你的策略"性格"�?/p>

  • SYMBOL:你要做哪个品种�?code>rb是螺纹钢�?code>2510�?025�?0月交割的合约。注意合约代码要改成当前的主力合约,不然可能已经过期了�?/li>
  • EXCHANGE:交易所。螺纹钢在上期所(SHFE)。其他品种对应不同交易所:豆粕在DCE(大商所),棉花在CZCE(郑商所),原油在INE(能源中心),股指在CFFEX(中金所)�?/li>
  • LOTS:每次买几手�?手螺纹钢=10吨,保证金大�?000-5000元。新手先1手练手�?/li>
  • PROFIT_TARGET:赚多少点就跑�?0个点×10�?500元利润(不含手续费)�?/li>
  • STOP_LOSS:亏多少点就跑�?0个点×10�?300元亏损�?/li>

为什么止盈比止损大? 因为50:30的比例意味着你赚一次的钱比亏一次的钱多。只要胜率超�?7.5%�?0÷80),长期就是赚钱的。这就是"盈亏�?的概念�?/p>

策略状态段

yesterday_high = None
position = 0
entry_price = 0
today_traded = False

这些变量记录策略�?记忆"。程序不像人,它没有脑子,所以你得用变量帮它记住�?/p>

  • 昨天最高价是多少?
  • 我现在有没有持仓�?/li>
  • 我买入的价格是多少?
  • 今天有没有已经交易过�?/li>

today_traded = False 这个特别重要。没有它,你的程序可能一分钟触发一次买入信号,一天买几十次——那不是策略,那是乱买�?/p>

买入逻辑

if not today_traded and yesterday_high is not None:
    is_yang_line = yesterday_close > yesterday_open
    if is_yang_line and bar.high_price > yesterday_high:
        app.buy(...)

三个条件同时满足才买�?/p>

1. 今天没交易过 �?防止重复下单

2. 昨天是阳�?/strong> �?昨天上涨了,今天突破才有意义。如果昨天暴跌,今天突破昨天高点可能只是反弹,不是趋势�?/p>

3. 当前价格突破昨天高点 �?这就�?突破"的核心定�?/p>

三个条件缺一个都不买。这就是策略�?纪律"�?/p>

止盈止损逻辑

if position > 0:
    profit = bar.close_price - entry_price
    if profit >= PROFIT_TARGET:
        app.sell(...)  # 止盈
    elif profit <= -STOP_LOSS:
        app.sell(...)  # 止损

持仓之后,每根K线都检查盈亏:

  • 赚够了(50点)�?卖出,落袋为�?/li>
  • 亏太多了�?0点)�?卖出,止损离�?/li>

为什么用 elif 而不是两�?if�?/strong> 因为止盈和止损不可能同时触发。要么赚够了,要么亏够了,不会既赚够又亏够�?/p>

下单函数

app.buy(symbol, exchange, price, volume, order_type)
app.sell(symbol, exchange, price, volume, order_type)

buy 是买入开仓,sell 是卖出平仓。参数一目了然:

  • symbol:哪个合�?/li>
  • exchange:哪个交易所
  • price:什么价格下�?/li>
  • volume:几�?/li>
  • order_type:限价单(LIMIT)还是市价单

限价�?vs 市价单:

  • 限价单:你指定一个价格,交易所帮你排队,等到有人愿意以这个价格成交。好处是价格确定,坏处是可能排不到�?/li>
  • 市价单:不管什么价格,立刻成交。好处是快,坏处是价格可能比你预期差(滑点)�?/li>

新手建议用限价单。你至少知道自己以什么价格下单了�?/p>


五、运行——看着程序下第一笔单

保存代码,运行:

python breakout_strategy.py

你会看到�?/p>

============================================================
🚀 突破策略启动
   品种:rb2510
   止盈�?0 �?   止损�?0 �?   手数�?
============================================================
📊 行情数据持续接收�?..
🚀 突破信号!当前最高价 3812.00 > 昨天高点 3805.00
   昨天是阳线:开�?3798.00,收�?3803.00
   📤 已发出买入指令:rb2510 1�?@ 3812.00
�?买入成交!价�?3812.00,数�?1�?   当前持仓�?手,入场价:3812.00
💰 止盈触发!盈�?52 �?>= 目标 50 �?   📤 已发出卖出指令(止盈�?�?卖出成交!价�?3864.00,数�?1�?   当前持仓�?�?

从信号到成交到止盈,全程自动。你不需要盯着屏幕,不需要犹豫,不需要手动点按钮�?/p>

你的程序替你做了所有事�?/strong>

这就是程序化交易。不是AI替你思考,不是机器替你决策。是你定好规则,机器替你执行�?/p>


六、这个策略能赚钱吗?

说实话:不一定�?/strong>

突破策略在趋势行情里表现不错,但在震荡行情里会被反复打脸——突破昨天高点,买入,然后价格回落,止损。再突破,再买入,再止损。一天亏三次�?/p>

这就是为什么下一集要�?strong>回测——用历史数据验证你的策略到底行不行,而不是靠感觉�?/p>

但不管能不能赚钱,这一集你学会了一件更重要的事�?strong>怎么把一个交易思路变成代码�?/strong>

思路 �?五个问题 �?四个函数 �?完整程序。这个流程,以后不管你写什么策略,都是一样的�?/p>


七、踩坑预�?/h2>

问题一�?合约代码不存�?

CTP: 合约 rb2510 不存�?

合约有生命周期。rb2510�?025�?0月交割的合约,到�?025�?0月就没了。你需要改成当前的主力合约。去SimNow交易端看一下,或者搜"螺纹钢主力合约代�?�?/p>

问题二:"资金不足"

CTP: 可用资金不足

SimNow模拟账户默认�?00万。如果你之前做了很多交易没平仓,可用资金可能不够。先平掉所有持仓再试�?/p>

问题三:下单了但没成�?/h3>

限价单需要排队。如果你的买入价格比当前市价低,可能一直排不到。改成市价单试试,或者把买入价格设成当前卖一价�?/p>

问题四:一天买了好多次

检�?today_traded 变量。如果忘了加这个限制,程序会在每根K线都判断一次突破条件,可能反复下单�?/p>


这一集你学到了什�?/h2>

1. 策略就是五个问题的答�?/strong>:品种、买入条件、数量、卖出条件、不做条�?/p>

2. 四个核心函数:on_tick(看行情)、on_bar(看K线做判断)、on_trade(确认成交)、on_order(委托状态)

3. 突破策略的完整代�?/strong>:从参数定义到止盈止损,每一步都有解�?/p>

4. 止盈止损的盈亏比�?0:30意味着胜率超过37.5%就长期盈�?/p>

5. 限价�?vs 市价�?/strong>:新手用限价单更安全


下一集预�?/h2>

�?集你学会�?写策�?。但这个策略到底能不能赚钱?你不知道�?/p>

下一集:回测——用过去三年的历史数据跑一遍你的策略,看它到底赚不赚、亏不亏、什么时候表现好、什么时候会崩�?/p>

回测是程序化交易最核心的能力。没有回测,你的策略就是赌博。有了回测,你的策略就是科学实验�?/p>

明天见�?/p>


*本系列面向零基础读者。有疑问加微�?futures886 或在评论区留言�?


果子量化 - AI驱动的期货程序化交易平台

官网�?a href="https://gocxh.com">gocxh.com | 微信:futures886