写了个交易机器人:双均线策略的实盘记录

为什么写交易机器人 做量化交易的人大概都有类似的想法:K 线不用一直盯着,让机器来执行策略,人在旁边看着就好。这样既不会被情绪左右,也不用天天坐在屏幕前。 这个想法本身没有问题,但实盘跑起来之后,你会发现很多细节是回测时根本想不到的。这篇文章主要记录我用 Python + CCXT 写的一个 OKX 合约交易机器人,从策略设计到部署上线的完整过程,希望能给同样在尝试的朋友一些参考。 策略选择 选了一个最简单的趋势跟踪策略:双均线交叉。 均线的逻辑很直观——短期均线(MA5)代表最近的价格趋势,长期均线(MA20)代表较长时间的趋势。当短期线上穿长期线时(金叉),意味着趋势可能向上,开多。当短期线下穿长期线时(死叉),趋势可能转弱,平多或开空。 这个策略的好处是容易理解,也容易执行。坏处是它在震荡行情里表现很差——价格反复穿越均线,频繁开平仓,手续费吃掉大部分利润。 核心代码逻辑 策略循环的核心逻辑大概是这样的: import ccxt import pandas as pd import time from datetime import datetime exchange = ccxt.okx({ 'apiKey': 'YOUR_API_KEY', 'secret': 'YOUR_SECRET_KEY', 'password': 'YOUR_API_PASSPHRASE', 'enableRateLimit': True, }) symbol = 'BTC-USDT-SWAP' timeframe = '1m' limit = 50 position_size = 50 # USDT leverage = 3 def get_ma_crossover(): """获取最新两根K线,计算MA5和MA20,判断是否金叉/死叉""" ohlcv = exchange.fetch_ohlcv(symbol, timeframe, limit=limit) df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume']) df['ma5'] = df['close'].rolling(window=5).mean() df['ma20'] = df['close'].rolling(window=20).mean() # 获取倒数第二根(上一根已收盘的K线)和倒数第三根的金叉状态 prev_ma5 = df['ma5'].iloc[-3] prev_ma20 = df['ma20'].iloc[-3] curr_ma5 = df['ma5'].iloc[-2] curr_ma20 = df['ma20'].iloc[-2] # 金叉:之前MA5 <= MA20,现在MA5 > MA20 golden_cross = prev_ma5 <= prev_ma20 and curr_ma5 > curr_ma20 # 死叉:之前MA5 >= MA20,现在MA5 < MA20 death_cross = prev_ma5 >= prev_ma20 and curr_ma5 < curr_ma20 return golden_cross, death_cross def get_position(): """查询当前持仓""" positions = exchange.fetch_positions([symbol]) for pos in positions: if pos['symbol'] == symbol and float(pos['contracts']) > 0: return pos return None def place_order(side, amount): """下单,带止盈止损""" # 先设置杠杆 exchange.set_leverage(leverage, symbol) # 开仓 order = exchange.create_market_order( symbol, side, amount, params={'leverage': leverage} ) # 获取开仓均价,设置止盈止损 # 这里需要根据实际成交价来设置 # 实际项目中会从 order 或后续查询中获取 fill price print(f"{datetime.now()} | {'多头' if side == 'buy' else '空头'}开仓 | 数量: {amount}") return order def main_loop(): """主循环""" print(f"策略启动: {symbol} | 时间周期: {timeframe} | 杠杆: {leverage}x") while True: try: golden, death = get_ma_crossover() position = get_position() if golden and not position: # 金叉且无持仓 → 开多 place_order('buy', position_size) elif death and position: # 死叉且有持仓 → 平多(可改为开空,根据策略偏好) exchange.create_market_order(symbol, 'sell', position['contracts']) print(f"{datetime.now()} | 平仓") time.sleep(10) # 每10秒检查一次 except Exception as e: print(f"错误: {e}") time.sleep(30) if __name__ == '__main__': main_loop() 实际项目中还需要处理很多边界情况:API 限频、网络断开重连、订单未完全成交、止盈止损的挂单管理等等。下面会详细说。 ...

2026-05-23 · 4 min · 761 words · Seb

对比了几款网页爬虫,我选了 Crawl4AI

爬虫工具的选择 写爬虫的需求大多数人都会遇到——想从某个网站上抓取一些内容做分析。 传统的爬虫工具大致分两类。一类是 Scrapy 这样的完整框架,功能强大,但配置复杂。写一个简单的抓取任务可能需要定义 Item、Pipeline、Middleware 等多个组件。另一类是 Requests + BeautifulSoup 的组合,上手简单,但遇到 JavaScript 渲染的页面就无能为力了。 Crawl4AI 的出现填补了两者之间的空白。它的定位是"专为 LLM 时代设计的爬虫工具"。 为什么选 Crawl4AI 最大的理由是它对 JavaScript 渲染的支持。现在的网页大部分是前后端分离的,数据通过异步请求加载,页面最终内容由 JavaScript 渲染生成。如果用传统爬虫去抓取这类网站,拿到的是空的 HTML 骨架,真正的数据根本不在这里。 Crawl4AI 内置了浏览器引擎,会自动执行页面上的 JavaScript,等页面完全渲染后再提取内容。这意味着你不必为了一个需要 JS 渲染的页面去额外配置 Selenium 或 Playwright。 另外,它的默认输出格式是 Markdown。这个细节在实际使用中很实用——抓取到的内容可以直接喂给 LLM 做分析,省去了格式转换的步骤。 安装和基本使用 Crawl4AI 的安装很简单,一行命令搞定: pip install crawl4ai 装完之后跑一个小例子试试: from crawl4ai import WebCrawler crawler = WebCrawler() result = crawler.run(url="https://example.com") print(result.markdown) 默认输出就是 Markdown,干净整洁。如果你需要原始 HTML,也可以拿到: print(result.html) # 原始 HTML print(result.extracted_content) # 提取后的内容 更高级的抓取配置 实际项目里,一条 URL 裸跑往往不够。Crawl4AI 提供了丰富的配置选项,这里分享几个常用的场景。 设置超时和等待 有的页面加载很慢,尤其是那些带大量图片和图表的网站。可以给爬虫指定最长等待时间: result = crawler.run( url="https://example.com/slow-page", wait_until="networkidle", # 等待网络请求空闲 timeout=30 # 最长等 30 秒 ) wait_until 参数有几个选项: ...

2026-05-23 · 2 min · 307 words · Seb