
En analyse technique, l’identification des quatre principaux schémas de structure de prix, à savoir les « hauts supérieurs » (HH), les « bas supérieurs » (HL), les « hauts inférieurs » (LH) et les « bas inférieurs » (LL), est essentielle pour évaluer la direction de la tendance du marché et les points de retournement potentiels. Ces schémas révèlent intuitivement l’équilibre dynamique entre l’offre et la demande, ainsi que le sentiment dominant (haussier ou baissier), fournissant ainsi une base objective aux décisions de trading.

Tendance haussièreDes sommets et des creux plus élevés sont des indicateurs clés d’une tendance haussière. Des sommets plus élevés se produisent lorsqu’un pic de prix dépasse le pic précédent, indiquant que les acheteurs poussent les prix à la hausse, reflétant la vigueur du marché. Des creux plus élevés se produisent lorsqu’une baisse de prix s’arrête à un niveau supérieur au précédent, indiquant que le marché maintient sa dynamique haussière. Ensemble, ces schémas indiquent une forte tendance haussière, identifiée sur un graphique par une série de pics et de creux ascendants.
Tendance baissièreDes sommets et des creux plus bas indiquent une tendance baissière. Des sommets plus bas se forment lorsqu’un pic de prix n’atteint pas le niveau du pic précédent, ce qui indique un affaiblissement de la pression acheteuse. Des creux plus bas se forment lorsque les prix chutent en dessous du creux précédent, reflétant une pression vendeuse accrue et un affaiblissement du marché. Ces schémas sont essentiels pour identifier les tendances baissières, qui se caractérisent sur un graphique des prix par une série de pics et de creux descendants.
Le marché des cryptomonnaies se caractérise par une forte volatilité, des échanges 24h/24 et 7j/7 et des tendances significatives influencées par le sentiment. Dans un tel environnement, il est d’autant plus important d’identifier précisément les tendances. En quantifiant la continuité des « hauts plus hauts » et des « bas plus hauts » ou des « bas plus bas », les tendances du marché peuvent être identifiées avec plus de précision, fournissant ainsi une base objective pour les décisions de trading.
La plateforme quantitative FMZ Inventor offre un environnement idéal pour le développement de tels indicateurs :
Avantage des données:
Environnement de développement:
Tester la commodité:
Sur la base de ces avantages, la plateforme FMZ a été choisie pour explorer les indicateurs de tendance de continuité des prix hauts et bas.
Avant de concevoir un indicateur, nous devons prendre en compte les différences entre le marché des crypto-monnaies et le marché boursier :
Sur la base de ces caractéristiques, le schéma de conception est le suivant :
Après une réflexion approfondie, nous avons adopté une méthode d’analyse basée sur les « données complètes de la veille » afin d’éviter les erreurs d’appréciation dues à des données incomplètes ce jour-là. La structure de base des données est la suivante :
# 每个币种的数据都单独存储
data = defaultdict(lambda: {
"daily_records": [], # 存储每日的昨天数据
"trend_buffer": [], # 当前趋势缓冲区
"patterns": [], # 完整的趋势模式
"current_trend": None, # 当前趋势状态
"last_processed_time": 0
})
Fonctions clés pour déterminer les tendances :
def is_trend_continuing(self, buffer, trend_type):
"""检查趋势是否持续"""
if len(buffer) < 2:
return False
curr = buffer[-1]
prev = buffer[-2]
if trend_type == "BULL":
# 牛市:High和Low都上升
return curr["High"] > prev["High"] and curr["Low"] > prev["Low"]
elif trend_type == "BEAR":
# 熊市:High和Low都下降
return curr["High"] < prev["High"] and curr["Low"] < prev["Low"]
return False
Gestion de l’état des tendances :
def analyze_trend_state(self, symbol):
"""分析趋势状态"""
storage = data[symbol]
buffer = storage["trend_buffer"]
current_trend = storage["current_trend"]
if current_trend is None:
# 尝试检测新趋势
new_trend = self.detect_new_trend(buffer)
if new_trend:
storage["current_trend"] = {
"type": new_trend,
"start_time": buffer[-2]["Time"],
"start_price": buffer[-2]["Close"],
"consecutive_days": 1
}
else:
# 检查现有趋势是否继续
if self.is_trend_continuing(buffer, current_trend["type"]):
current_trend["consecutive_days"] += 1
else:
# 趋势中断,记录完整模式
if current_trend["consecutive_days"] >= MIN_CONSECUTIVE:
# 保存趋势记录
self.save_pattern(symbol, current_trend, buffer)
L’idée clé de la conception est d’exiger des points hauts et des points basen même tempsSatisfaire aux changements continus et atteindre une période de confirmation minimale de 3 jours peut réduire considérablement les erreurs de jugement. Le taux de rendement statistique représente la hausse ou la baisse entre le cours d’ouverture au début de la tendance et le cours de clôture à la fin de celle-ci.
Sur la base des données historiques de backtest de la plateforme FMZ de 2020 à juin 2025, voici les performances réelles des trois principales devises au cours des 10 derniers cycles de tendance complets :
| taper | date de début | Date de fin | Durée | Rendement |
|---|---|---|---|---|
| Marché baissier | 2025-05-29 | 2025-06-01 | 3 | -5.38% |
| Marché haussier | 2025-05-19 | 2025-05-22 | 3 | 6.73% |
| Marché haussier | 2025-05-06 | 2025-05-09 | 3 | 26.94% |
| Marché haussier | 2025-04-24 | 2025-04-27 | 3 | -0.17% |
| Marché baissier | 2025-03-25 | 2025-03-30 | 5 | -13.13% |
| Marché haussier | 2025-03-21 | 2025-03-24 | 3 | 5.04% |
| Marché baissier | 2025-01-06 | 2025-01-10 | 4 | -10.86% |
| Marché haussier | 2025-01-01 | 2025-01-06 | 5 | 11.2% |
| Marché baissier | 2024-12-17 | 2024-12-20 | 3 | -15.5% |
| Marché baissier | 2024-12-07 | 2024-12-10 | 3 | -9.96% |
Caractéristiques de performance de l’ETH:
| taper | date de début | Date de fin | Durée | Rendement |
|---|---|---|---|---|
| Marché haussier | 2025-06-06 | 2025-06-11 | 5 | 7.78% |
| Marché baissier | 2025-06-03 | 2025-06-06 | 3 | -0.78% |
| Marché baissier | 2025-05-27 | 2025-05-31 | 4 | -4.37% |
| Marché baissier | 2025-05-22 | 2025-05-25 | 3 | -2.63% |
| Marché haussier | 2025-05-06 | 2025-05-09 | 3 | 8.4% |
| Marché baissier | 2025-05-02 | 2025-05-05 | 3 | -2.37% |
| Marché haussier | 2025-04-20 | 2025-04-23 | 3 | 10.07% |
| Marché haussier | 2025-04-09 | 2025-04-13 | 4 | 10.25% |
| Marché baissier | 2025-03-26 | 2025-03-29 | 3 | -5.53% |
| Marché baissier | 2025-03-08 | 2025-03-11 | 3 | -5.81% |
Caractéristiques de performance du BTC:
| taper | date de début | Date de fin | Durée | Rendement |
|---|---|---|---|---|
| Marché haussier | 2025-06-06 | 2025-06-11 | 5 | 5.46% |
| Marché baissier | 2025-06-03 | 2025-06-06 | 3 | -2.73% |
| Marché haussier | 2025-05-19 | 2025-05-22 | 3 | 4.63% |
| Marché haussier | 2025-05-05 | 2025-05-10 | 5 | 11.95% |
| Marché haussier | 2025-04-20 | 2025-04-23 | 3 | 2.44% |
| Marché haussier | 2025-04-09 | 2025-04-12 | 3 | 7.63% |
| Marché haussier | 2025-03-14 | 2025-03-17 | 3 | 8.18% |
| Marché baissier | 2025-03-08 | 2025-03-11 | 3 | -7.49% |
| Marché haussier | 2025-02-10 | 2025-02-13 | 3 | 9.66% |
| Marché baissier | 2025-01-31 | 2025-02-03 | 3 | -12.2% |
Caractéristiques de performance du BNB:
Lors de l’analyse des données des dix derniers cycles de tendance de ces trois devises, certains phénomènes intéressants ont été découverts.
À propos de la durée de la tendance
La plupart des tendances se terminent en 3 à 5 jours environ, ce qui correspond à l’opinion générale sur le marché des cryptomonnaies : il évolue très rapidement. La période de confirmation minimale initialement fixée à 3 jours reste raisonnable, car elle permet de filtrer certaines fluctuations aléatoires de la journée et de ne pas manquer d’opportunités en raison d’une attente trop longue. Le Bitcoin est le plus stable à cet égard, et la durée de la tendance est relativement régulière.
Les différences dans le « caractère » des différentes monnaies
Ces trois monnaies ont chacune leurs propres caractéristiques. La performance récente de l’ETH est en effet plus remarquable, et il est possible qu’il ait stagné trop longtemps, ce qui explique l’ampleur de la volatilité du rebond. Du 6 au 9 mai, il peut grimper de 26,94 % en 3 jours, ce qui est surprenant, mais on observe également un « marché haussier » de -0,17 % qui laisse perplexe. Le BTC est indéniablement plus stable. Malgré la multiplication des marchés baissiers récemment, la volatilité reste acceptable. Le BNB a réservé de nombreuses surprises, avec un marché haussier représentant 70 %, et le ratio risque/rendement semble être le meilleur.
Quelques observations sur le jugement de tendance
À en juger par les résultats, cet indicateur simple a néanmoins capturé certains moments clés. Par exemple, la hausse de 26,94 % de l’ETH, les multiples cycles haussiers du BTC et du BNB, et plusieurs rappels opportuns de marchés baissiers. Bien sûr, il existe aussi des points confus, comme le « marché haussier » de -0,17 %, qui montre que l’algorithme a encore une marge de progression.
Pour être honnête, cet outil vous aide principalementDécouvrez à quoi ressemble le marché actuellement:
Il faut préciser que cet outilCe n’est certainement pas pour prédire l’avenir.:
En fonctionnement réel, certaines limitations ont également été constatées :
Un peu lent à répondre:Comme il faut 3 jours pour confirmer, il est pratiquement impossible de saisir la tendance dans les premiers jours
Parfois, je « juge mal les gens »:Comme le « marché haussier » de -0,17 % de l’ETH, cela montre que dans certains cas particuliers, le jugement de l’algorithme peut être erroné
Le marché latéral est un casse-têteLorsque le marché fluctue dans une fourchette, le signal peut changer fréquemment, ce qui est ennuyeux
Rien que regarder le prix est un peu monotone: Ne pas prendre en compte des facteurs tout aussi importants tels que le volume des échanges et les actualités
Sur la base des observations faites durant cette période, je pense qu’il y a plusieurs directions à essayer :
Ajuster les paramètres pour différentes devises: Pour une devise volatile comme l’ETH, des conditions de confirmation plus strictes peuvent être requises, tandis qu’une devise relativement stable comme le BNB peut réduire le délai de confirmation. Vous pouvez également définir un seuil de rendement minimum pour filtrer les signaux présentant des rendements trop faibles.
Ajoutez un jugement auxiliaire: Par exemple, combiner les changements de volume de transactions pour vérifier si la tendance est fiable, ou prendre en compte la plage de fluctuation des prix pour éviter d’être induit en erreur par des changements mineurs.
Optimiser l’algorithme lui-même: Améliorer la logique de jugement de l’interruption de tendance pour réduire les erreurs de jugement ; ajouter une note de force à la tendance pour distinguer les tendances fortes et faibles ; établir un mécanisme de traitement spécial pour certaines situations anormales.
Cet outil simple de surveillance du marché transforme certains concepts d’analyse technique traditionnels en un système automatisé. Grâce à la plateforme FMZ, nous avons réussi à créer un outil capable de surveiller l’état du marché des cryptomonnaies en temps réel.
Son principal intérêt réside dans la fourniture d’un enregistrement relativement objectif des conditions du marché, ce qui peut nous aider à :
À mesure que les données s’accumulent, cet outil deviendra de plus en plus précieux. Bien sûr, il ne s’agit que d’un outil d’analyse parmi d’autres et on ne peut pas s’attendre à ce qu’il résolve tous les problèmes, mais comme point de départ, il reste très intéressant.
'''backtest
start: 2020-01-01 00:00:00
end: 2025-06-16 00:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Binance","currency":"BTC_USDT"}]
'''
import json
from datetime import datetime
from collections import defaultdict
# 配置参数
SYMBOLS = ["ETH_USDT", "BTC_USDT", "BNB_USDT"]
MIN_CONSECUTIVE = 3 # 最少连续天数
MAX_HISTORY = 1000 # 最大历史记录数
# 全局数据存储
data = defaultdict(lambda: {
"daily_records": [], # 存储每日的昨天数据
"trend_buffer": [], # 当前趋势缓冲区
"patterns": [], # 完整的趋势模式
"current_trend": None, # 当前趋势状态
"last_processed_time": 0
})
class TrendAnalyzer:
def get_yesterday_data(self, records):
"""获取昨天的完整数据(records[-2])"""
if len(records) < 2:
return None
return records[-2] # 昨天的完整K线数据
def is_trend_continuing(self, buffer, trend_type):
"""检查趋势是否持续"""
if len(buffer) < 2:
return False
curr = buffer[-1]
prev = buffer[-2]
if trend_type == "BULL":
# 牛市:High和Low都上升
return curr["High"] > prev["High"] and curr["Low"] > prev["Low"]
elif trend_type == "BEAR":
# 熊市:High和Low都下降
return curr["High"] < prev["High"] and curr["Low"] < prev["Low"]
return False
def detect_new_trend(self, buffer):
"""从缓冲区检测新趋势"""
if len(buffer) < 2:
return None
curr = buffer[-1]
prev = buffer[-2]
# 检查是否开始牛市趋势
if curr["High"] > prev["High"] and curr["Low"] > prev["Low"]:
return "BULL"
# 检查是否开始熊市趋势
elif curr["High"] < prev["High"] and curr["Low"] < prev["Low"]:
return "BEAR"
return None
def process_daily_data(self, symbol, records):
"""处理每日数据"""
if not records or len(records) < 2:
return
storage = data[symbol]
yesterday_data = self.get_yesterday_data(records)
if not yesterday_data or yesterday_data["Time"] <= storage["last_processed_time"]:
return # 没有新的昨天数据
# 更新处理时间
storage["last_processed_time"] = yesterday_data["Time"]
# 添加到每日记录
storage["daily_records"].append(yesterday_data)
if len(storage["daily_records"]) > MAX_HISTORY:
storage["daily_records"] = storage["daily_records"][-MAX_HISTORY:]
# 添加到趋势缓冲区
storage["trend_buffer"].append(yesterday_data)
# 分析趋势
self.analyze_trend_state(symbol)
def analyze_trend_state(self, symbol):
"""分析趋势状态"""
storage = data[symbol]
buffer = storage["trend_buffer"]
current_trend = storage["current_trend"]
if len(buffer) < 2:
return
if current_trend is None:
# 尝试检测新趋势
new_trend = self.detect_new_trend(buffer)
if new_trend:
storage["current_trend"] = {
"type": new_trend,
"start_time": buffer[-2]["Time"], # 趋势从前一天开始
"start_price": buffer[-2]["Close"],
"start_open": buffer[-2]["Open"],
"consecutive_days": 1
}
Log(f"{symbol} 检测到{new_trend}趋势开始")
else:
# 没有趋势,只保留最近的数据
storage["trend_buffer"] = buffer[-1:]
else:
# 检查现有趋势是否继续
if self.is_trend_continuing(buffer, current_trend["type"]):
# 趋势继续
current_trend["consecutive_days"] += 1
# 检查是否达到最小天数要求
if current_trend["consecutive_days"] == MIN_CONSECUTIVE:
trend_name = "牛市" if current_trend["type"] == "BULL" else "熊市"
Log(f"{symbol} {trend_name}趋势确认! 连续{MIN_CONSECUTIVE}天")
else:
# 趋势中断
if current_trend["consecutive_days"] >= MIN_CONSECUTIVE:
# 记录完整的趋势
end_data = buffer[-2] # 趋势在前一天结束
duration = current_trend["consecutive_days"]
start_price = current_trend["start_open"]
end_price = end_data["Close"]
return_pct = round((end_price - start_price) / start_price * 100, 2)
storage["patterns"].append({
"trend": current_trend["type"],
"start_time": current_trend["start_time"],
"end_time": end_data["Time"],
"duration": duration,
"return": return_pct
})
trend_name = "牛市" if current_trend["type"] == "BULL" else "熊市"
Log(f"{symbol} {trend_name}趋势结束,持续{duration}天,收益{return_pct}%")
# 重置趋势状态,重新开始检测
storage["current_trend"] = None
storage["trend_buffer"] = buffer[-2:] # 保留最近两天数据重新开始
# 立即检测新趋势
self.analyze_trend_state(symbol)
def generate_tables():
"""生成所有统计表格"""
tables = []
# 概览表
overview_rows = []
for symbol in SYMBOLS:
storage = data[symbol]
if not storage["daily_records"]:
continue
patterns = storage["patterns"]
current_trend = storage["current_trend"]
# 计算统计数据
bull_patterns = [p for p in patterns if p["trend"] == "BULL"]
bear_patterns = [p for p in patterns if p["trend"] == "BEAR"]
stats = {
"bull_avg_return": round(sum(p["return"] for p in bull_patterns) / len(bull_patterns), 2) if bull_patterns else 0,
"bear_avg_return": round(sum(p["return"] for p in bear_patterns) / len(bear_patterns), 2) if bear_patterns else 0,
"bull_avg_days": round(sum(p["duration"] for p in bull_patterns) / len(bull_patterns), 1) if bull_patterns else 0,
"bear_avg_days": round(sum(p["duration"] for p in bear_patterns) / len(bear_patterns), 1) if bear_patterns else 0
}
# 当前状态
current_status = "震荡"
current_return = 0
current_days = 0
consecutive = 0
if current_trend and storage["daily_records"]:
latest_price = storage["daily_records"][-1]["Close"]
start_price = current_trend["start_open"]
current_return = round((latest_price - start_price) / start_price * 100, 2)
current_days = current_trend["consecutive_days"]
current_status = "牛市" if current_trend["type"] == "BULL" else "熊市"
consecutive = current_trend["consecutive_days"]
overview_rows.append([
symbol.replace("_USDT", ""),
current_status,
str(current_days),
f"{current_return}%",
str(consecutive),
str(len(bull_patterns)),
str(len(bear_patterns)),
f"{stats['bull_avg_return']}%",
f"{stats['bear_avg_return']}%",
f"{stats['bull_avg_days']}天",
f"{stats['bear_avg_days']}天"
])
tables.append({
"type": "table",
"title": "每日高低价趋势监控(基于昨日完整数据)",
"cols": ["币种", "状态", "持续", "收益", "强度", "牛市次数", "熊市次数", "牛市均收益", "熊市均收益", "牛市均天数", "熊市均天数"],
"rows": overview_rows
})
# 趋势缓冲区分析表
buffer_rows = []
for symbol in SYMBOLS:
storage = data[symbol]
buffer = storage["trend_buffer"]
current_trend = storage["current_trend"]
if not buffer:
continue
latest_price = buffer[-1]["Close"]
buffer_size = len(buffer)
# 显示最近几天的High/Low变化
if len(buffer) >= 2:
recent_highs = [f"{r['High']:.0f}" for r in buffer[-min(5, len(buffer)):]]
recent_lows = [f"{r['Low']:.0f}" for r in buffer[-min(5, len(buffer)):]]
high_trend = " → ".join(recent_highs)
low_trend = " → ".join(recent_lows)
else:
high_trend = f"{buffer[-1]['High']:.0f}"
low_trend = f"{buffer[-1]['Low']:.0f}"
trend_status = "无趋势"
if current_trend:
trend_status = f"{'牛市' if current_trend['type'] == 'BULL' else '熊市'}{current_trend['consecutive_days']}天"
buffer_rows.append([
symbol.replace("_USDT", ""),
f"{latest_price:.2f}",
trend_status,
str(buffer_size),
high_trend,
low_trend
])
tables.append({
"type": "table",
"title": "趋势缓冲区状态",
"cols": ["币种", "价格", "当前趋势", "缓冲区", "High变化", "Low变化"],
"rows": buffer_rows
})
# 历史记录表
for symbol in SYMBOLS:
patterns = [p for p in data[symbol]["patterns"] if p["duration"] >= MIN_CONSECUTIVE]
coin_name = symbol.replace("_USDT", "")
if not patterns:
tables.append({
"type": "table",
"title": f"{coin_name} 历史趋势",
"cols": ["类型", "开始", "结束", "天数", "收益"],
"rows": [["无数据", "-", "-", "-", "-"]]
})
continue
rows = []
for p in sorted(patterns, key=lambda x: x["end_time"], reverse=True)[:10]: # 只显示最近10条
rows.append([
"牛市" if p["trend"] == "BULL" else "熊市",
datetime.fromtimestamp(p["start_time"] / 1000).strftime('%Y-%m-%d'),
datetime.fromtimestamp(p["end_time"] / 1000).strftime('%Y-%m-%d'),
str(p["duration"]),
f"{p['return']}%"
])
tables.append({
"type": "table",
"title": f"{coin_name} 历史趋势",
"cols": ["类型", "开始", "结束", "天数", "收益"],
"rows": rows
})
return tables
def main():
analyzer = TrendAnalyzer()
Log("趋势分析系统启动 - 基于昨日完整数据的逐日分析")
Log("牛市定义: High和Low连续上升≥3天")
Log("熊市定义: High和Low连续下降≥3天")
while True:
try:
# 处理每个币种的数据
for symbol in SYMBOLS:
records = exchange.GetRecords(symbol)
analyzer.process_daily_data(symbol, records)
# 生成并显示表格
tables = generate_tables()
LogStatus('`' + json.dumps(tables) + '`')
except Exception as e:
Log(f"错误: {str(e)}")
Sleep(1000 * 60 * 60) # 24小时
def onexit():
total = sum(len(data[s]["patterns"]) for s in SYMBOLS)
Log(f"系统停止, 共识别 {total} 个趋势模式")