惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

W
WeLiveSecurity
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Hacker News - Newest:
Hacker News - Newest: "LLM"
Cloudbric
Cloudbric
V
Visual Studio Blog
L
LangChain Blog
A
About on SuperTechFans
B
Blog
T
Tenable Blog
罗磊的独立博客
Hacker News: Ask HN
Hacker News: Ask HN
Blog — PlanetScale
Blog — PlanetScale
博客园 - 三生石上(FineUI控件)
The Register - Security
The Register - Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
P
Palo Alto Networks Blog
U
Unit 42
WordPress大学
WordPress大学
D
Darknet – Hacking Tools, Hacker News & Cyber Security
N
News and Events Feed by Topic
T
Threat Research - Cisco Blogs
C
Check Point Blog
Security Latest
Security Latest
M
MIT News - Artificial intelligence
Application and Cybersecurity Blog
Application and Cybersecurity Blog
宝玉的分享
宝玉的分享
P
Proofpoint News Feed
NISL@THU
NISL@THU
Forbes - Security
Forbes - Security
S
Securelist
Security Archives - TechRepublic
Security Archives - TechRepublic
Hugging Face - Blog
Hugging Face - Blog
aimingoo的专栏
aimingoo的专栏
Latest news
Latest news
GbyAI
GbyAI
T
Troy Hunt's Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LINUX DO - 热门话题
V2EX - 技术
V2EX - 技术
小众软件
小众软件
Google DeepMind News
Google DeepMind News
K
Kaspersky official blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
O
OpenAI News
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
N
Netflix TechBlog - Medium
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Google DeepMind News
Google DeepMind News
P
Proofpoint News Feed

lucifer的网络博客

我不知道的《易经》 | lucifer的网络博客 加密交易的风险管理:仓位、止损与资金分配 | lucifer的网络博客 永续合约:无到期日的杠杆交易是如何运作的 | lucifer的网络博客 代币经济学:如何判断一个代币值不值得买 | lucifer的网络博客 稳定币机制全解:从 USDT 到 UST 崩盘的启示 DeFi 保险:谁来保护你的链上资产? | lucifer的网络博客 Claude Code 高级指南:驾驭上下文的艺术 | lucifer的网络博客 NotebookLM:AI 驱动的知识炼金术,瞬间转化复杂信息为易懂洞见 | lucifer的网络博客 当下流动性池分析 | lucifer的网络博客 苹果AI转型:Siri升级与生态潜力 | lucifer的网络博客 我们是如何让 JSON.stringify 的速度提升两倍以上的 | lucifer的网络博客 ACP:AI 代理协作协议在 Web3 空投自动化中的应用 | lucifer的网络博客 从零构建一个真正工作的简单搜索引擎 | lucifer的网络博客 限制即提示:算法解题的隐秘指引 | lucifer的网络博客 如何阅读财报:从入门到进阶指南 | lucifer的网络博客 Freqtrade 量化风暴:Python 铸就的加密交易自动化帝国 | lucifer的网络博客 DePIN 觉醒:Web3 如何让你的闲置硬件变黄金 | lucifer的网络博客 自己动手制作 Web3 代币估值表 | lucifer的网络博客 当 RWA 遇上幸福小区玉米 | lucifer的网络博客 探索 DeFi 借贷与收益率交易的无限潜力 | lucifer的网络博客 Uniswap V4:更灵活、更高效的去中心化交易所 | lucifer的网络博客 Web3 科学家之如何查看鲸鱼挂单数据 | lucifer的网络博客 抖音也开始搞外卖大战了? | lucifer的网络博客 Web3 的 Anti MEV:深入剖析“夹”与反制之道 | lucifer的网络博客 《小菜的交易系统》-一个完整的简易的交易系统 | lucifer的网络博客 回炉重铸, 91 天见证不一样的自己(第 16 期)
Freqtrade 进阶:把多个弱信号拧成一根绳——多信号评分策略实战 | lucifer的网络博客
2026-07-20 · via lucifer的网络博客

大家好,我是 Lucifer,又来聊聊 Web3 的那些有趣事儿了。今天咱们来聊聊 Freqtrade。

上一篇我们从零搭好了 Freqtrade,写了个最简单的 SMA 交叉策略。很多人跑完回测后跟我说:“这策略也太简单了,实盘根本扛不住。”

说得对。那篇是入门用的“Hello World”。真正能活下来的策略,从来不是依赖某一个“神级指标”,而是把一堆看起来不怎么样的弱信号,用正确的方式组合起来。

今天这篇是正式续篇。我们会把「组合弱信号」这个核心思想,落地成一个能直接在 Freqtrade 里跑的策略。

先补一点前置知识

在写策略之前,先把两个最基础的概念说清楚。

1. 什么是信号?

信号不是“我觉得这个币要涨”这种模糊感觉,而是一个可量化、有方向、可重复的数据点。比如:

  • RSI 从 30 以下回升
  • 快线上穿慢线
  • 成交量放大到均线的 1.3 倍

这些都是信号。单个信号通常很弱,准确率往往只有 50% 多一点点。

2. dataframe.loc 是干什么的?

Freqtrade 策略的核心是一张表格(DataFrame),每一行是一根 K 线,每一列是价格或指标。

dataframe.loc[条件, 列名] = 值 的意思是:
找到符合条件的那些 K 线,给它们打上标记。

比如:

1
2
3
4
dataframe.loc[
(dataframe['rsi'] < 30) & (dataframe['volume'] > 0),
'enter_long'
] = 1

这句话的意思就是:“凡是 RSI 低于 30 且有成交量的 K 线,都标记为可以买入。”

后面所有买卖逻辑,本质上都是在用 .loc 给不同的行打分或打标记。

为什么要组合多个弱信号?

单一信号最大的问题是:它大部分时候都是错的

量化里把单个信号的准确度叫 IC(Information Coefficient)。机构级信号的 IC 通常只有 0.05~0.15,意思是它跟市场真实走势的相关性非常弱。

但主动管理基本定律告诉我们:

IR = IC × √N

系统整体表现 = 单个信号准确度 × 独立信号数量的平方根。

所以,与其苦苦寻找一个“永远正确”的神级信号,不如收集几十个“稍微有点准”的弱信号,然后把它们正确地组合起来。噪音会互相抵消,优势会叠加。

这就是今天策略的核心思路。

策略思路

我们不追求某一个指标特别准,而是让多个弱信号一起“投票”。

具体做法:

  1. 选取 6 个相关性较低的常见信号(动量、均值回归、成交量、趋势强度等)。
  2. 每个信号根据自己的条件给当前 K 线打分(有的 +1,有的 +2)。
  3. 把所有分数加总,得到一个综合置信度分数。
  4. 只有当综合分数达到设定阈值时,才允许开仓。
  5. 出场逻辑反过来,用反向信号打分,达到阈值就平仓。

这样做的好处是:

  • 不再要求所有条件同时成立(那会让信号极少)。
  • 不同信号可以有不同权重(比如 RSI 回升给 2 分,普通交叉只给 1 分)。
  • 噪音被分散,真正有优势的时刻更容易被识别出来。

这已经是文章里“组合引擎”思想的简化落地版。真正的机构还会做去均值、正交化、残差加权等更复杂的步骤,但对我们现阶段来说,评分投票已经足够体现核心逻辑。

完整策略代码(辅助参考)

把下面代码保存为 user_data/strategies/MultiSignalScore.py 即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
from freqtrade.strategy import IStrategy, IntParameter
from pandas import DataFrame
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib


class MultiSignalScore(IStrategy):
"""
多弱信号评分策略
核心思想:用多个低 IC 信号投票,提升整体系统表现
"""

INTERFACE_VERSION = 3
timeframe = '15m'
can_short = False

minimal_roi = {
"0": 0.035,
"40": 0.02,
"90": 0.01
}
stoploss = -0.055
trailing_stop = True
trailing_stop_positive = 0.012
trailing_stop_positive_offset = 0.022
trailing_only_offset_is_reached = True

startup_candle_count = 50


buy_score_threshold = IntParameter(4, 8, default=5, space='buy')
sell_score_threshold = IntParameter(3, 6, default=4, space='sell')

def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:

dataframe['sma_fast'] = ta.SMA(dataframe, timeperiod=10)
dataframe['sma_slow'] = ta.SMA(dataframe, timeperiod=30)
macd = ta.MACD(dataframe)
dataframe['macd'] = macd['macd']
dataframe['macdsignal'] = macd['macdsignal']
dataframe['macdhist'] = macd['macdhist']


dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
dataframe['bb_lower'] = bollinger['lower']
dataframe['bb_middle'] = bollinger['mid']
dataframe['bb_upper'] = bollinger['upper']


dataframe['adx'] = ta.ADX(dataframe)
dataframe['volume_sma'] = ta.SMA(dataframe, timeperiod=20, price='volume')

return dataframe

def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['buy_score'] = 0


dataframe.loc[
(dataframe['sma_fast'] > dataframe['sma_slow']) &
(dataframe['sma_fast'].shift(1) <= dataframe['sma_slow'].shift(1)),
'buy_score'] += 1


dataframe.loc[
(dataframe['macdhist'] > 0) &
(dataframe['macdhist'].shift(1) <= 0),
'buy_score'] += 1


dataframe.loc[
(dataframe['rsi'] > 30) &
(dataframe['rsi'].shift(1) <= 30),
'buy_score'] += 2


dataframe.loc[
(dataframe['close'] < dataframe['bb_lower'] * 1.01),
'buy_score'] += 1


dataframe.loc[
(dataframe['volume'] > dataframe['volume_sma'] * 1.3),
'buy_score'] += 1


dataframe.loc[
(dataframe['adx'] > 20) &
(dataframe['adx'] > dataframe['adx'].shift(1)),
'buy_score'] += 1


dataframe.loc[
(dataframe['buy_score'] >= self.buy_score_threshold.value) &
(dataframe['volume'] > 0),
'enter_long'] = 1

return dataframe

def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['sell_score'] = 0

dataframe.loc[
(dataframe['sma_fast'] < dataframe['sma_slow']) &
(dataframe['sma_fast'].shift(1) >= dataframe['sma_slow'].shift(1)),
'sell_score'] += 1

dataframe.loc[
(dataframe['macdhist'] < 0) &
(dataframe['macdhist'].shift(1) >= 0),
'sell_score'] += 1

dataframe.loc[
(dataframe['rsi'] > 70),
'sell_score'] += 2

dataframe.loc[
(dataframe['close'] > dataframe['bb_upper'] * 0.99),
'sell_score'] += 1

dataframe.loc[
(dataframe['sell_score'] >= self.sell_score_threshold.value) &
(dataframe['volume'] > 0),
'exit_long'] = 1

return dataframe

怎么跑起来

下载数据后执行回测:

1
freqtrade backtesting --strategy MultiSignalScore --timerange 20240701-20250701 --export trades

想优化阈值参数,可以用:

1
freqtrade hyperopt --strategy MultiSignalScore --hyperopt-loss SharpeHyperOptLoss --spaces buy sell --epochs 100

总结

一个现实中真正可用的策略基本就是按照这个方式去叠加信号, 给不同信号分配不同的权重等等。

量化最反直觉的一点是:你越执着于寻找“永远正确”的信号,你就越容易亏钱。真正能持续活下来的人,都在默默收集那些“稍微有点准”的弱信号,然后用数学把它们拧成一股绳。

 上一页

易经 读后感