
В области технического анализа выявление четырёх основных паттернов ценовой структуры: «более высокие максимумы (HH)», «более высокие минимумы (HL)», «более низкие максимумы (LH)» и «более низкие минимумы (LL)» — является краеугольным камнем оценки направления рыночного тренда и потенциальных точек разворота. Эти паттерны интуитивно отражают динамический баланс рыночного спроса и предложения, а также преобладающие настроения (бычьи или медвежьи), обеспечивая объективную основу для принятия торговых решений.

Бычий тренд: Более высокие максимумы и более высокие минимумы являются ключевыми индикаторами бычьего тренда. Более высокие максимумы возникают, когда пик цены превышает предыдущий, указывая на то, что покупатели толкают цены вверх, отражая силу рынка. Более высокие минимумы возникают, когда падение цены останавливается на уровне выше предыдущего падения, указывая на то, что рынок сохраняет восходящий импульс. В совокупности эти паттерны указывают на сильный восходящий тренд, который на графике отображается серией растущих пиков и впадин.
Медвежий тренд: Более низкие максимумы и более низкие минимумы указывают на медвежий тренд. Более низкие максимумы формируются, когда пик цены не достигает уровня предыдущего пика, что указывает на ослабление давления покупателей. Более низкие минимумы формируются, когда цены опускаются ниже предыдущего минимума, что отражает возросшее давление продавцов и слабость рынка. Эти паттерны важны для определения нисходящих трендов, которые на ценовом графике отображаются серией снижающихся пиков и впадин.
Рынок криптовалют характеризуется высокой волатильностью, круглосуточной торговлей и значительными трендами, определяемыми настроениями рынка. В таких условиях точное выявление трендовых моделей становится ещё важнее. Количественная оценка непрерывности «более высокие максимумы, более высокие минимумы» или «более низкие максимумы, более низкие минимумы» позволяет точнее определять рыночные тренды, обеспечивая объективную основу для принятия торговых решений.
Количественная платформа FMZ Inventor обеспечивает идеальную среду для разработки таких показателей:
Преимущество данных:
Среда разработки:
Тестирование удобства:
На основании этих преимуществ платформа FMZ была выбрана для изучения индикаторов тенденции непрерывности высоких и низких цен.
Прежде чем разрабатывать индикатор, нам необходимо рассмотреть различия между рынком криптовалют и фондовым рынком:
Исходя из этих характеристик, схема проектирования выглядит следующим образом:
После глубокого размышления мы приняли метод анализа, основанный на «вчерашних полных данных», чтобы избежать ошибочных суждений, вызванных неполными данными на день. Основная структура данных выглядит следующим образом:
# 每个币种的数据都单独存储
data = defaultdict(lambda: {
"daily_records": [], # 存储每日的昨天数据
"trend_buffer": [], # 当前趋势缓冲区
"patterns": [], # 完整的趋势模式
"current_trend": None, # 当前趋势状态
"last_processed_time": 0
})
Ключевые функции определения тенденций:
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 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)
Основная идея дизайна — это требование высоких и низких точек.в то же времяУдовлетворить непрерывные изменения и достичь минимального периода подтверждения в 3 дня, что может значительно сократить неверное суждение. Статистика нормы прибыли — это увеличение или уменьшение от цены открытия в начале тренда до цены закрытия в конце тренда.
На основе исторических данных бэктестинга платформы FMZ с 2020 года по июнь 2025 года, ниже представлена фактическая динамика трех основных валют за последние 10 полных циклов тренда:
| тип | Дата начала | Дата окончания | Продолжительность | Урожай |
|---|---|---|---|---|
| Медвежий рынок | 2025-05-29 | 2025-06-01 | 3 | -5.38% |
| Бычий рынок | 2025-05-19 | 2025-05-22 | 3 | 6.73% |
| Бычий рынок | 2025-05-06 | 2025-05-09 | 3 | 26.94% |
| Бычий рынок | 2025-04-24 | 2025-04-27 | 3 | -0.17% |
| Медвежий рынок | 2025-03-25 | 2025-03-30 | 5 | -13.13% |
| Бычий рынок | 2025-03-21 | 2025-03-24 | 3 | 5.04% |
| Медвежий рынок | 2025-01-06 | 2025-01-10 | 4 | -10.86% |
| Бычий рынок | 2025-01-01 | 2025-01-06 | 5 | 11.2% |
| Медвежий рынок | 2024-12-17 | 2024-12-20 | 3 | -15.5% |
| Медвежий рынок | 2024-12-07 | 2024-12-10 | 3 | -9.96% |
Характеристики производительности ETH:
| тип | Дата начала | Дата окончания | Продолжительность | Урожай |
|---|---|---|---|---|
| Бычий рынок | 2025-06-06 | 2025-06-11 | 5 | 7.78% |
| Медвежий рынок | 2025-06-03 | 2025-06-06 | 3 | -0.78% |
| Медвежий рынок | 2025-05-27 | 2025-05-31 | 4 | -4.37% |
| Медвежий рынок | 2025-05-22 | 2025-05-25 | 3 | -2.63% |
| Бычий рынок | 2025-05-06 | 2025-05-09 | 3 | 8.4% |
| Медвежий рынок | 2025-05-02 | 2025-05-05 | 3 | -2.37% |
| Бычий рынок | 2025-04-20 | 2025-04-23 | 3 | 10.07% |
| Бычий рынок | 2025-04-09 | 2025-04-13 | 4 | 10.25% |
| Медвежий рынок | 2025-03-26 | 2025-03-29 | 3 | -5.53% |
| Медвежий рынок | 2025-03-08 | 2025-03-11 | 3 | -5.81% |
Характеристики производительности BTC:
| тип | Дата начала | Дата окончания | Продолжительность | Урожай |
|---|---|---|---|---|
| Бычий рынок | 2025-06-06 | 2025-06-11 | 5 | 5.46% |
| Медвежий рынок | 2025-06-03 | 2025-06-06 | 3 | -2.73% |
| Бычий рынок | 2025-05-19 | 2025-05-22 | 3 | 4.63% |
| Бычий рынок | 2025-05-05 | 2025-05-10 | 5 | 11.95% |
| Бычий рынок | 2025-04-20 | 2025-04-23 | 3 | 2.44% |
| Бычий рынок | 2025-04-09 | 2025-04-12 | 3 | 7.63% |
| Бычий рынок | 2025-03-14 | 2025-03-17 | 3 | 8.18% |
| Медвежий рынок | 2025-03-08 | 2025-03-11 | 3 | -7.49% |
| Бычий рынок | 2025-02-10 | 2025-02-13 | 3 | 9.66% |
| Медвежий рынок | 2025-01-31 | 2025-02-03 | 3 | -12.2% |
Эксплуатационные характеристики BNB:
При анализе данных последних десяти трендовых циклов этих трех валют были обнаружены некоторые интересные явления.
О продолжительности тренда
Большинство трендов заканчиваются примерно через 3–5 дней, что, по сути, соответствует общему мнению о рынке криптовалют — он меняется очень быстро. Первоначальный минимальный срок подтверждения в 3 дня всё ещё вполне разумен, поскольку позволяет отфильтровать случайные колебания в течение дня и не упускать возможности из-за слишком долгого ожидания. BTC в этом отношении наиболее стабилен, а продолжительность тренда относительно стабильна.
Различия в «характере» разных валют
У этих трёх валют действительно есть свои особенности. Недавняя динамика ETH действительно более привлекательна, и, возможно, он слишком долго находился в состоянии покоя, поэтому волатильность отскока очень велика. С 6 по 9 мая он может вырасти на 26,94% за 3 дня, что удивительно, но есть и «бычий рынок» -0,17%, который заставляет людей чесать голову. BTC, несомненно, стабильнее. Хотя в последнее время медвежьих рынков стало больше, волатильность всё ещё приемлемая. BNB преподнёс всем немало сюрпризов: на бычий рынок приходится 70%, а соотношение риска и доходности, похоже, самое лучшее.
Некоторые наблюдения о тенденциях оценки
Судя по результатам, этот простой индикатор всё же уловил некоторые ключевые моменты. Например, рост ETH на 26,94%, многочисленные циклы бычьего рынка BTC и BNB, а также несколько своевременных напоминаний о медвежьем рынке. Конечно, есть и некоторые сбивающие с толку моменты, например, «бычий рынок» -0,17%, который показывает, что алгоритму ещё есть куда совершенствоваться.
Честно говоря, этот инструмент в основном помогает вамУзнайте, как сейчас обстоят дела на рынке:
Необходимо четко указать, что этот инструментЭто определенно не для предсказания будущего.:
В ходе реальной эксплуатации также были обнаружены некоторые ограничения:
Немного медленно реагирует: Поскольку для подтверждения требуется 3 дня, в первые несколько дней практически невозможно уловить тенденцию
Иногда я «неправильно оцениваю людей».:Как и в случае с «бычьим рынком» ETH -0,17%, это показывает, что в некоторых особых случаях суждение алгоритма может быть неверным.
Боковой рынок — это головная боль:Когда рынок колеблется в пределах диапазона, сигнал может часто меняться, что раздражает.
Просто смотреть на цену немного однообразно: Неспособность учесть такие важные факторы, как объем торгов и новости
На основе наблюдений за этот период я думаю, что есть несколько направлений, которые можно попробовать:
Настройте параметры для разных валют: Для такой нестабильной валюты, как ETH, могут потребоваться более строгие условия подтверждения, в то время как относительно стабильная валюта, как BNB, может сократить время подтверждения. Вы также можете установить минимальный порог доходности, чтобы отфильтровать сигналы со слишком низкой доходностью.
Добавьте некоторые вспомогательные суждения: Например, объединение изменений в объеме торгов для проверки надежности тренда или учет диапазона колебаний цен, чтобы не быть введенными в заблуждение незначительными изменениями.
Оптимизация самого алгоритма: Улучшить логику оценки прерывания тренда, чтобы уменьшить количество неверных суждений; добавить рейтинг силы тренда, чтобы различать сильные и слабые тренды; создать специальный механизм обработки для некоторых ненормальных ситуаций.
Этот простой инструмент мониторинга рынка действительно превращает некоторые традиционные концепции технического анализа в автоматизированную систему. Благодаря удобству платформы FMZ мы успешно создали инструмент, который может отслеживать состояние рынка криптовалют в режиме реального времени.
Его главная ценность заключается в предоставлении относительно объективной информации о рыночных условиях, которая может помочь нам:
По мере накопления данных этот инструмент будет становиться всё более ценным. Конечно, это лишь один из многих инструментов анализа, и от него нельзя ожидать решения всех проблем, но в качестве отправной точки, я думаю, он всё равно очень интересен.
'''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} 个趋势模式")