2
Suivre
319
Abonnés

Une brève discussion sur le développement d'un indicateur de tendance de crypto-monnaie

Créé le: 2025-06-23 16:08:06, Mis à jour le: 2025-06-24 09:54:54
comments   0
hits   516

Une brève discussion sur le développement d’un indicateur de tendance de crypto-monnaie

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.

Caractéristiques principales des marchés haussiers et baissiers

Une brève discussion sur le développement d’un indicateur de tendance de crypto-monnaie

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.

La nécessité d’une identification quantitative des tendances

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.

Pourquoi choisir la plateforme FMZ

La plateforme quantitative FMZ Inventor offre un environnement idéal pour le développement de tels indicateurs :

Avantage des données

  • Mise à disposition gratuite de données historiques provenant des principales bourses
  • Données complètes de K-line couvrant les principales crypto-monnaies
  • Qualité des données fiable et mises à jour en temps opportun

Environnement de développement

  • Page d’édition de code légère et rapide
  • Prend en charge plusieurs langages de programmation tels que Python
  • Bibliothèque de fonctions d’analyse technique riche et intégrée

Tester la commodité

  • Fonction de backtesting complète
  • Surveillance et visualisation en temps réel
  • Pratique pour l’analyse simultanée de plusieurs devises

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.

Caractéristiques du marché des cryptomonnaies

Avant de concevoir un indicateur, nous devons prendre en compte les différences entre le marché des crypto-monnaies et le marché boursier :

  • Trading 24 heures sur 24, pas de fermeture de marché
  • La volatilité est énorme et il n’est pas rare que le marché augmente ou diminue de 20 % en une journée.
  • Il y a beaucoup d’investisseurs particuliers et le trading émotionnel est évident
  • Les données historiques ne sont pas longues, la plupart des devises n’ont que quelques années

Sur la base de ces caractéristiques, le schéma de conception est le suivant :

  • L’utilisation de données quotidiennes permet de filtrer le bruit intrajournalier sans prendre de retard
  • Définissez 3 jours comme période de confirmation minimale pour équilibrer précision et rapidité
  • Surveillez plusieurs devises courantes pour vérification en même temps

Implémenté sur la plateforme FMZ

Conception de l’algorithme de base

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
})

La logique fondamentale de l’identification des tendances

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.

Résultats réels des opérations et analyse des données

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 :

Analyse des résultats des tests ETH

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

  • La performance la plus remarquable a été le marché haussier du 6 au 9 mai, qui a connu une augmentation significative de 26,94 % en seulement trois jours.
  • Le marché haussier moyen dure 3,4 jours, avec un rendement moyen de 9,97 %.
  • Le marché baissier dure en moyenne 3,6 jours, avec une baisse moyenne de -10,97 %.
  • Extrêmement volatile, la plus instable des trois devises

Analyse des résultats des tests BTC

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

  • Les marchés baissiers dominent, avec 6 cycles sur 10 étant des marchés baissiers
  • Le marché haussier moyen dure 3,75 jours, avec un rendement moyen de 9,13 %.
  • Le marché baissier moyen a duré 3,17 jours et la baisse moyenne a été de -3,58 %.
  • La performance globale est relativement équilibrée, avec une volatilité modérée

Analyse des résultats des tests BNB

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

  • Les marchés haussiers sont dominants, avec 7 cycles sur 10 étant des marchés haussiers
  • Le marché haussier moyen a duré 3,43 jours, avec un rendement moyen de 7,14 %.
  • Le marché baissier dure en moyenne 3 jours, avec une baisse moyenne de -7,47 %
  • La performance est la plus stable, avec relativement peu de conditions de marché extrêmes

Quelques résultats intéressants derrière les données

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.

A quoi sert cet outil ?

Ce qu’il peut faire pour vous

Pour être honnête, cet outil vous aide principalementDécouvrez à quoi ressemble le marché actuellement

  • Vous indiquer si la tendance actuelle est à la hausse, à la baisse ou fluctue latéralement
  • Gardez une trace de la durée de cette tendance et de ses performances.
  • Fournir une base de jugement relativement objective, pas entièrement basée sur des sentiments
  • À en juger par les données réelles, il est assez efficace pour identifier les tendances à court terme de 3 à 5 jours.

Ce qu’il ne peut pas faire

Il faut préciser que cet outilCe n’est certainement pas pour prédire l’avenir.

  • Il ne vous dira pas si cela va monter ou descendre demain.
  • Je ne peux pas prédire dans quelle mesure cela va augmenter ou diminuer.
  • Il ne peut pas remplacer votre propre contrôle des risques et votre gestion de fonds
  • Lorsque le marché évolue latéralement, cela peut donner des signaux confus

Quelques problèmes rencontrés lors de l’utilisation

En fonctionnement réel, certaines limitations ont également été constatées :

  1. Un peu lent à répondre:Comme il faut 3 jours pour confirmer, il est pratiquement impossible de saisir la tendance dans les premiers jours

  2. 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é

  3. 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

  4. 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

Comment pouvons-nous l’améliorer ensuite ?

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.

Retour sur cette exploration

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 à :

  • Avoir une compréhension macroéconomique de la situation globale du marché
  • Filtrer certaines devises populaires grâce à des données historiques
  • Fournir un support de données pour une analyse plus approfondie

À 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} 个趋势模式")