MEXC 策略分析

बनाया गया: 27 नवंबर 2024

का उपयोग करके उत्तर दिया गया O1 Preview द्वारा Chat01

प्रश्न

import sys

设置事件循环策略,解决Windows上的事件循环问题

if sys.platform.startswith('win'):
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

import ccxt.async_support as ccxt # 使用异步版本的ccxt
import pandas as pd
import datetime
import smtplib
import config
import os
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import asyncio
from ta.trend import EMAIndicator
import logging

配置日志记录

script_dir = os.path.dirname(os.path.abspath(file))
log_folder = os.path.join(script_dir, 'logs')
if not os.path.exists(log_folder):
os.makedirs(log_folder)
log_filename = os.path.join(log_folder, f"log_{datetime.datetime.now().strftime('%Y%m%d')}.log")
logging.basicConfig(filename=log_filename,
level=logging.INFO,
format='%(asctime)s %(levelname)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')

1. 使用ccxt库连接MEXC交易所

print("正在连接到 MEXC 交易所...")
logging.info("正在连接到 MEXC 交易所...")

async def main():
# 初始化交易所连接
print("正在初始化交易所连接...")
logging.info("正在初始化交易所连接...")
exchange = ccxt.mexc({
'apiKey': config.apiKey,
'secret': config.secret,
'password': config.password,
'enableRateLimit': True,
'timeout': 60000,
'aiohttp_proxy': config.proxy, # 设置异步模式下的代理
})

text
# 2. 获取所有合约币种 print("正在获取所有合约币种...") logging.info("正在获取所有合约币种...") await exchange.load_markets() symbols = [market['symbol'] for market in exchange.markets.values() if market['active'] and market['type'] == 'swap'] print(f"共获取到 {len(symbols)} 个合约币种。") logging.info(f"共获取到 {len(symbols)} 个合约币种。") # 3. 获取这些币种的上一天K线数据,并筛选出交易量前100的币种 print("正在获取上一天K线数据并筛选交易量前100的币种...") logging.info("正在获取上一天K线数据并筛选交易量前100的币种...") data_list = [] semaphore = asyncio.Semaphore(config.max_concurrency) # 控制并发数量 async def fetch_volume(symbol): async with semaphore: try: # 获取上一天的1天K线数据(limit=2,取前一天完整的K线) ohlcv = await exchange.fetch_ohlcv(symbol, timeframe='1d', limit=2) if len(ohlcv) >= 2: # 前一天的K线 previous_candle = ohlcv[-2] volume = previous_candle[5] data_list.append({ 'symbol': symbol, 'volume': volume }) print(f"{symbol} 数据获取成功,交易量:{volume}") logging.info(f"{symbol} 数据获取成功,交易量:{volume}") else: print(f"{symbol} 无足够的K线数据。") logging.warning(f"{symbol} 无足够的K线数据。") except Exception as e: print(f"获取 {symbol} 数据时出错:{e}") logging.error(f"获取 {symbol} 数据时出错:{e}") tasks = [asyncio.ensure_future(fetch_volume(symbol)) for symbol in symbols] await asyncio.gather(*tasks) # 关闭交易所连接 await exchange.close() # 筛选交易量前100的币种 df_volume = pd.DataFrame(data_list) df_volume = df_volume.sort_values(by='volume', ascending=False) top_symbols = df_volume.head(config.top_volume_limit)['symbol'].tolist() print(f"筛选出交易量前{config.top_volume_limit}的币种,共 {len(top_symbols)} 个。") logging.info(f"筛选出交易量前{config.top_volume_limit}的币种,共 {len(top_symbols)} 个。") # 4. 在不同时间框架上计算技术指标并筛选符合条件的币种 print("正在计算技术指标并进行多时间框架分析...") logging.info("正在计算技术指标并进行多时间框架分析...") exchange = ccxt.mexc({ 'apiKey': config.apiKey, 'secret': config.secret, 'password': config.password, 'enableRateLimit': True, 'timeout': 60000, 'aiohttp_proxy': config.proxy, }) selected_coins = [] semaphore = asyncio.Semaphore(config.max_concurrency) # 控制并发数量 async def analyze_symbol(symbol): async with semaphore: try: # 存储不同时间框架的分析结果 timeframes_results = [] for timeframe in config.timeframes: print(f"获取 {symbol} 在 {timeframe} 时间框架的K线数据...") logging.info(f"获取 {symbol} 在 {timeframe} 时间框架的K线数据...") limit = max(config.vegas_long_period, config.ema_long_period, 20) + 50 # 确保有足够的数据 ohlcv = await exchange.fetch_ohlcv(symbol, timeframe=timeframe, limit=limit) if len(ohlcv) < limit: print(f"{symbol} 在 {timeframe} 时间框架的数据不足,跳过。") logging.warning(f"{symbol} 在 {timeframe} 时间框架的数据不足,跳过。") continue # 将数据转换为DataFrame df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume']) df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms') df.set_index('timestamp', inplace=True) # 剔除最新的未完成K线 df = df.iloc[:-1] # 计算EMA指标 df['ema_short'] = EMAIndicator(df['close'], window=config.ema_short_period).ema_indicator() df['ema_long'] = EMAIndicator(df['close'], window=config.ema_long_period).ema_indicator() # 计算维加斯通道 df['vegas_short'] = EMAIndicator(df['close'], window=config.vegas_short_period).ema_indicator() df['vegas_long'] = EMAIndicator(df['close'], window=config.vegas_long_period).ema_indicator() # 获取最新的完整K线数据 latest = df.iloc[-1] # 策略条件 # 条件1:价格位于维加斯通道上方 condition1 = latest['close'] > latest['vegas_long'] # 条件2:EMA短期线上穿长期线(多头排列) condition2 = (df['ema_short'].iloc[-2] <= df['ema_long'].iloc[-2]) and (df['ema_short'].iloc[-1] > df['ema_long'].iloc[-1]) # 条件3:交易量大于平均值 average_volume = df['volume'].rolling(window=20).mean().iloc[-1] condition3 = latest['volume'] > average_volume # 裸K线策略条件 # 检查趋势(高低点抬高) def is_uptrend(df, periods=20): df_recent = df[-periods:] lows = df_recent['low'] highs = df_recent['high'] trend = all(lows.iloc[i] > lows.iloc[i - 1] and highs.iloc[i] > highs.iloc[i - 1] for i in range(1, len(df_recent))) return trend # 检查看涨吞没形态 def is_bullish_engulfing(df): prev_candle = df.iloc[-2] latest_candle = df.iloc[-1] # 前一根是阴线,当前是阳线 condition_a = prev_candle['close'] < prev_candle['open'] and latest_candle['close'] > latest_candle['open'] # 当前K线的实体完全包住前一根K线的实体 condition_b = latest_candle['close'] > prev_candle['open'] and latest_candle['open'] < prev_candle['close'] return condition_a and condition_b # 检查锤子线形态 def is_hammer(df): latest_candle = df.iloc[-1] body = abs(latest_candle['close'] - latest_candle['open']) lower_wick = min(latest_candle['open'], latest_candle['close']) - latest_candle['low'] upper_wick = latest_candle['high'] - max(latest_candle['open'], latest_candle['close']) # 实体较小,下影线较长,上影线较短 return lower_wick > 2 * body and upper_wick < body condition4 = is_uptrend(df, periods=20) and (is_bullish_engulfing(df) or is_hammer(df)) # 记录符合的条件 conditions_met = [] if condition1 and condition2 and condition3: conditions_met.append('指标条件') if condition4: conditions_met.append('裸K线策略') # 检查条件组合 if conditions_met: print(f"{symbol} 在 {timeframe} 时间框架上符合条件:{','.join(conditions_met)}") logging.info(f"{symbol} 在 {timeframe} 时间框架上符合条件:{','.join(conditions_met)}") timeframes_results.append({ 'timeframe': timeframe, 'conditions': conditions_met, 'latest': latest # 保存最新的K线数据 }) else: print(f"{symbol} 在 {timeframe} 时间框架上不符合条件。") logging.info(f"{symbol} 在 {timeframe} 时间框架上不符合条件。") # 控制请求频率 await asyncio.sleep(exchange.rateLimit / 1000) # 筛选满足条件的币种 timeframes_required = config.timeframes_required # 需要满足条件的时间框架数量 if len(timeframes_results) >= timeframes_required: # 汇总符合条件的时间框架和条件 timeframes_info = '; '.join([f"{res['timeframe']}:{','.join(res['conditions'])}" for res in timeframes_results]) print(f"{symbol} 在至少 {timeframes_required} 个时间框架上符合条件,加入列表。") logging.info(f"{symbol} 在至少 {timeframes_required} 个时间框架上符合条件,加入列表。") # 获取最新的K线数据(以最后一个时间框架的数据为准,也可以选择其他方式) latest = timeframes_results[-1]['latest'] selected_coins.append({ '币种': symbol, '最新价格': latest['close'], '交易量': latest['volume'], 'EMA短期': latest['ema_short'], 'EMA长期': latest['ema_long'], '维加斯短期': latest['vegas_short'], '维加斯长期': latest['vegas_long'], '符合条件': timeframes_info }) else: print(f"{symbol} 在满足条件的时间框架数量不足,跳过。") logging.info(f"{symbol} 在满足条件的时间框架数量不足,跳过。") except Exception as e: print(f"处理 {symbol} 时出错:{e}") logging.error(f"处理 {symbol} 时出错:{e}") tasks = [asyncio.ensure_future(analyze_symbol(symbol)) for symbol in top_symbols] await asyncio.gather(*tasks) # 关闭交易所连接 await exchange.close() # 5. 保存结果并发送邮件通知 if selected_coins: df_selected = pd.DataFrame(selected_coins) current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') # 创建保存CSV文件的文件夹 folder_name = os.path.join(script_dir, 'selected_coins') if not os.path.exists(folder_name): os.makedirs(folder_name) filename = os.path.join(folder_name, f"选币结果_{datetime.datetime.now().strftime('%Y%m%d%H%M%S')}.csv") # 将数值格式化(可选) df_selected['最新价格'] = df_selected['最新价格'].apply(lambda x: f"{x:.6f}") df_selected['交易量'] = df_selected['交易量'].apply(lambda x: f"{x:.2f}") df_selected['EMA短期'] = df_selected['EMA短期'].apply(lambda x: f"{x:.6f}") df_selected['EMA长期'] = df_selected['EMA长期'].apply(lambda x: f"{x:.6f}") df_selected['维加斯短期'] = df_selected['维加斯短期'].apply(lambda x: f"{x:.6f}") df_selected['维加斯长期'] = df_selected['维加斯长期'].apply(lambda x: f"{x:.6f}") try: df_selected.to_csv(filename, index=False, encoding='utf-8-sig') print(f"选币结果已保存到 {filename}") logging.info(f"选币结果已保存到 {filename}") except Exception as e: print(f"写入文件时出错:{e}") logging.error(f"写入文件时出错:{e}") # 发送邮件通知 print("正在发送邮件...") logging.info("正在发送邮件...") smtp_server = config.smtp_server smtp_port = config.smtp_port sender_email = config.sender_email receiver_email = config.receiver_email password = config.email_password # 请在config.py中使用不同的变量名避免混淆 subject = '选币结果通知' # 将数据转换为HTML表格 df_email = df_selected[['币种', '最新价格', '交易量', 'EMA短期', 'EMA长期', '维加斯短期', '维加斯长期', '符合条件']] df_email_html = df_email.to_html(index=False) # 邮件正文,使用HTML格式 body = f"""<p>您好,</p> <p>请查收最新的选币结果。</p> <p>当前时间:{current_time}</p> <p>筛选依据:</p> <ul> <li>条件1:价格位于维加斯通道上方(维加斯长期EMA)</li> <li>条件2:EMA短期线上穿EMA长期线</li> <li>条件3:交易量大于20期平均值</li> <li>裸K线策略:上升趋势中的看涨吞没形态或锤子线</li> </ul> {df_email_html} <p>此致<br/>敬礼</p> """ # 创建邮件 message = MIMEMultipart() message['From'] = sender_email message['To'] = receiver_email message['Subject'] = subject message.attach(MIMEText(body, 'html', 'utf-8')) try: server = smtplib.SMTP_SSL(smtp_server, smtp_port) server.login(sender_email, password) server.sendmail(sender_email, receiver_email, message.as_string()) server.quit() print("邮件发送成功!") logging.info("邮件发送成功!") except Exception as e: print(f"邮件发送失败:{e}") logging.error(f"邮件发送失败:{e}") else: print("没有符合条件的币种。") logging.info("没有符合条件的币种。")

运行主函数

if name == "main":
asyncio.run(main())
这是我的脚本,你帮我分析下脚本运行的详细步骤,我关于筛选策略,想改成3 sma技术去筛选,我们后面去分析更改

विचार

Analyzing the script

I’m looking at the script to understand its precise steps. It connects to the MEXC exchange using ccxt, retrieves market data, calculates indicators, and sends email alerts.

उत्तर

Certainly! Let's analyze your script step by step to understand its functionality and execution flow. This will help us identify where to implement the changes for the "3 SMA" screening strategy later on.


Overview of the Script

Your script is designed to:

  1. Connect to the MEXC cryptocurrency exchange using the ccxt library.
  2. Fetch all available swap (perpetual futures) symbols from the exchange.
  3. Retrieve historical OHLCV (Open, High, Low, Close, Volume) data for these symbols.
  4. Calculate technical indicators (EMA, Vegas channels) and apply a multi-timeframe analysis.
  5. Implement a selection strategy based on specific conditions and candlestick patterns.
  6. Save the selected coins to a CSV file and send an email notification with the results.

Detailed Step-by-Step Analysis

1. Initial Setup

  • Import Necessary Libraries:

    python
    import sys import asyncio import ccxt.async_support as ccxt import pandas as pd import datetime import smtplib import config import os from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from ta.trend import EMAIndicator import logging
  • Set Event Loop Policy for Windows Compatibility:

    python
    if sys.platform.startswith('win'): import asyncio asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
  • Configure Logging:

    • Creates a logs directory if it doesn't exist.
    • Configures the logging settings, including filename, log level, format, and date format.
    python
    script_dir = os.path.dirname(os.path.abspath(__file__)) log_folder = os.path.join(script_dir, 'logs') if not os.path.exists(log_folder): os.makedirs(log_folder) log_filename = os.path.join(log_folder, f"log_{datetime.datetime.now().strftime('%Y%m%d')}.log") logging.basicConfig(filename=log_filename, level=logging.INFO, format='%(asctime)s %(levelname)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S')

2. Connecting to MEXC Exchange

  • Initialize the Exchange Connection:

    python
    exchange = ccxt.mexc({ 'apiKey': config.apiKey, 'secret': config.secret, 'password': config.password, 'enableRateLimit': True, 'timeout': 60000, 'aiohttp_proxy': config.proxy, })
    • Uses API credentials from a config module.
    • Enables rate limiting and sets a timeout.
    • Configures an HTTP proxy if needed.

3. Fetching All Swap Symbols

  • Load Markets and Filter Symbols:

    python
    await exchange.load_markets() symbols = [market['symbol'] for market in exchange.markets.values() if market['active'] and market['type'] == 'swap']
    • Loads all available markets from the exchange.
    • Filters for active swap markets (perpetual futures).
    • Stores the symbols in a list.

4. Fetching Historical Data and Volume Filtering

  • Initialize Data Collection:

    python
    data_list = [] semaphore = asyncio.Semaphore(config.max_concurrency)
    • Initializes an empty list to store data.
    • Uses a semaphore to control the maximum number of concurrent API requests.
  • Define Async Function to Fetch Volume Data:

    python
    async def fetch_volume(symbol): async with semaphore: # Fetch OHLCV data # Extract previous day's candle # Append volume data to data_list
  • Fetch OHLCV Data for Each Symbol:

    • For each symbol, fetch the OHLCV data with a timeframe of 1 day and a limit of 2 (to get the previous day's complete candle).
    python
    ohlcv = await exchange.fetch_ohlcv(symbol, timeframe='1d', limit=2)
  • Extract Previous Day's Volume:

    python
    if len(ohlcv) >= 2: previous_candle = ohlcv[-2] volume = previous_candle[5] data_list.append({ 'symbol': symbol, 'volume': volume })
  • Handle Exceptions and Insufficient Data:

    • Logs warnings if data is insufficient.
    • Logs errors if fetching data fails.
  • Run All Fetch Tasks Concurrently:

    python
    tasks = [asyncio.ensure_future(fetch_volume(symbol)) for symbol in symbols] await asyncio.gather(*tasks)
  • Close Exchange Connection:

    python
    await exchange.close()
  • Filter Top Symbols by Volume:

    • Converts data_list to a DataFrame.
    • Sorts by volume in descending order.
    • Selects the top N symbols based on volume (configured in config.top_volume_limit).
    python
    df_volume = pd.DataFrame(data_list) df_volume = df_volume.sort_values(by='volume', ascending=False) top_symbols = df_volume.head(config.top_volume_limit)['symbol'].tolist()

5. Technical Indicator Calculation and Multi-Timeframe Analysis

  • Reinitialize Exchange Connection:

    python
    exchange = ccxt.mexc({ 'apiKey': config.apiKey, 'secret': config.secret, 'password': config.password, 'enableRateLimit': True, 'timeout': 60000, 'aiohttp_proxy': config.proxy, })
  • Initialize Selected Coins List and Semaphore:

    python
    selected_coins = [] semaphore = asyncio.Semaphore(config.max_concurrency)
  • Define Async Function to Analyze Symbols:

    python
    async def analyze_symbol(symbol): async with semaphore: # For each timeframe, fetch data and calculate indicators # Apply strategy conditions # Collect results if conditions are met
  • Iterate Over Configured Timeframes:

    python
    for timeframe in config.timeframes: # Fetch OHLCV data # Convert to DataFrame # Calculate EMA and Vegas channels # Apply strategy conditions
  • Fetch OHLCV Data for Each Timeframe:

    • Determines the required limit based on the longest period needed for indicators plus some buffer.
    python
    limit = max(config.vegas_long_period, config.ema_long_period, 20) + 50 ohlcv = await exchange.fetch_ohlcv(symbol, timeframe=timeframe, limit=limit)
  • Convert Data to DataFrame and Preprocess:

    python
    df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume']) df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms') df.set_index('timestamp', inplace=True) # Remove the latest incomplete candle df = df.iloc[:-1]
  • Calculate Technical Indicators:

    • EMA Short and Long Periods:

      python
      df['ema_short'] = EMAIndicator(df['close'], window=config.ema_short_period).ema_indicator() df['ema_long'] = EMAIndicator(df['close'], window=config.ema_long_period).ema_indicator()
    • Vegas Channels:

      python
      df['vegas_short'] = EMAIndicator(df['close'], window=config.vegas_short_period).ema_indicator() df['vegas_long'] = EMAIndicator(df['close'], window=config.vegas_long_period).ema_indicator()
  • Retrieve Latest Complete Candle Data:

    python
    latest = df.iloc[-1]
  • Define Strategy Conditions:

    • Condition 1: Price is above the Vegas long EMA.

      python
      condition1 = latest['close'] > latest['vegas_long']
    • Condition 2: EMA short-term crosses above EMA long-term (golden cross).

      python
      condition2 = (df['ema_short'].iloc[-2] <= df['ema_long'].iloc[-2]) and (df['ema_short'].iloc[-1] > df['ema_long'].iloc[-1])
    • Condition 3: Volume is greater than the 20-period moving average.

      python
      average_volume = df['volume'].rolling(window=20).mean().iloc[-1] condition3 = latest['volume'] > average_volume
    • Condition 4: Price action patterns (Bullish Engulfing or Hammer in an uptrend).

      • Determine Uptrend:

        python
        def is_uptrend(df, periods=20): df_recent = df[-periods:] lows = df_recent['low'] highs = df_recent['high'] trend = all(lows.iloc[i] > lows.iloc[i - 1] and highs.iloc[i] > highs.iloc[i - 1] for i in range(1, len(df_recent))) return trend
      • Bullish Engulfing Pattern:

        python
        def is_bullish_engulfing(df): prev_candle = df.iloc[-2] latest_candle = df.iloc[-1] condition_a = prev_candle['close'] < prev_candle['open'] and latest_candle['close'] > latest_candle['open'] condition_b = latest_candle['close'] > prev_candle['open'] and latest_candle['open'] < prev_candle['close'] return condition_a and condition_b
      • Hammer Pattern:

        python
        def is_hammer(df): latest_candle = df.iloc[-1] body = abs(latest_candle['close'] - latest_candle['open']) lower_wick = min(latest_candle['open'], latest_candle['close']) - latest_candle['low'] upper_wick = latest_candle['high'] - max(latest_candle['open'], latest_candle['close']) return lower_wick > 2 * body and upper_wick < body
      • Check Condition 4:

        python
        condition4 = is_uptrend(df, periods=20) and (is_bullish_engulfing(df) or is_hammer(df))
  • Aggregate Conditions Met:

    • Collects the names of the conditions that are met.
    python
    conditions_met = [] if condition1 and condition2 and condition3: conditions_met.append('指标条件') # Indicator conditions if condition4: conditions_met.append('裸K线策略') # Price action strategy
  • Check if Symbol Meets Required Timeframes:

    • If the symbol meets the conditions in enough timeframes (as specified in config.timeframes_required), it's added to the selected_coins list.
    python
    if len(timeframes_results) >= timeframes_required: selected_coins.append({ '币种': symbol, '最新价格': latest['close'], '交易量': latest['volume'], 'EMA短期': latest['ema_short'], 'EMA长期': latest['ema_long'], '维加斯短期': latest['vegas_short'], '维加斯长期': latest['vegas_long'], '符合条件': timeframes_info })
  • Handle Exceptions and Control Rate Limit:

    • Logs errors if any occur during processing.
    • Waits for exchange.rateLimit milliseconds between requests.

6. Saving Results and Sending Email Notification

  • Check if Any Coins Were Selected:

    python
    if selected_coins: # Proceed to save results and send email else: print("没有符合条件的币种。")
  • Save Selected Coins to CSV:

    • Converts selected_coins to a DataFrame.
    • Formats numerical values for better readability.
    • Saves the DataFrame to a CSV file in a selected_coins directory.
    python
    df_selected = pd.DataFrame(selected_coins) # Format numerical columns df_selected.to_csv(filename, index=False, encoding='utf-8-sig')
  • Prepare Email Content:

    • Sets up email server settings using the config module.
    • Converts the DataFrame to an HTML table for the email body.
    • Constructs the email subject and body, including the current time and strategy conditions.
    python
    smtp_server = config.smtp_server smtp_port = config.smtp_port sender_email = config.sender_email receiver_email = config.receiver_email password = config.email_password # Convert DataFrame to HTML df_email_html = df_email.to_html(index=False) body = f"""<p>您好,</p> <p>请查收最新的选币结果。</p> <p>当前时间:{current_time}</p> <p>筛选依据:</p> <ul> <li>条件1:价格位于维加斯通道上方(维加斯长期EMA)</li> <li>条件2:EMA短期线上穿EMA长期线</li> <li>条件3:交易量大于20期平均值</li> <li>裸K线策略:上升趋势中的看涨吞没形态或锤子线</li> </ul> {df_email_html} <p>此致<br/>敬礼</p> """
  • Send the Email:

    • Creates a MIME multipart message.
    • Attaches the HTML body to the email.
    • Logs in to the SMTP server and sends the email.
    python
    message = MIMEMultipart() message['From'] = sender_email message['To'] = receiver_email message['Subject'] = subject message.attach(MIMEText(body, 'html', 'utf-8')) server = smtplib.SMTP_SSL(smtp_server, smtp_port) server.login(sender_email, password) server.sendmail(sender_email, receiver_email, message.as_string()) server.quit()

7. Main Execution Block

  • Run the Asynchronous Main Function:

    python
    if __name__ == "__main__": asyncio.run(main())

Summary of the Script's Functionality

  • Data Retrieval:

    • Connects to the MEXC exchange and retrieves all active swap symbols.
    • Fetches the previous day's volume data for these symbols.
    • Selects the top N symbols based on trading volume.
  • Technical Analysis:

    • For each selected symbol, fetches OHLCV data for multiple timeframes.

    • Calculates EMA indicators and Vegas channels.

    • Checks for specific conditions:

      • Price above the Vegas long EMA.
      • EMA short-term crossing above EMA long-term.
      • Volume greater than the 20-period average.
      • Presence of bullish candlestick patterns in an uptrend (Bullish Engulfing or Hammer).
  • Selection Criteria:

    • Symbols that meet the conditions in a specified number of timeframes are selected.
    • Collects relevant data for the selected symbols.
  • Output and Notification:

    • Saves the selected symbols and their data to a CSV file.
    • Sends an email notification with the results in an HTML table format.

Next Steps: Modifying the Screening Strategy to Use the "3 SMA" Technique

Now that we've analyzed the script in detail, we can proceed to modify the screening strategy to implement the "3 SMA" technique. This will involve:

  1. Understanding the "3 SMA" Strategy:

    • Typically involves using three Simple Moving Averages (SMAs) of different periods.
    • Commonly, traders look for crossovers between short-term, medium-term, and long-term SMAs to identify trends and potential entry points.
  2. Identifying Where to Implement Changes:

    • Replace or modify the current EMA and Vegas channel calculations.
    • Adjust the strategy conditions to use the "3 SMA" crossovers.
    • Ensure that the script still aligns with your selection criteria and objectives.
  3. Updating the Script:

    • Modify the indicator calculations to use SMAs instead of EMAs.
    • Define new conditions based on the "3 SMA" technique.
    • Test the modified script to ensure it works as expected.

Feel free to share any specific details or preferences about the "3 SMA" strategy you want to implement. We can then work together to adjust the script accordingly.

प्रश्न

请思考和回答过程都用中文回答。
# 剔除最新的未完成K线
df = df.iloc[:-1]
这一步不需要了
# 策略条件
# 条件1:价格位于维加斯通道上方
condition1 = latest['close'] > latest['vegas_long']

text
# 条件2:EMA短期线上穿长期线(多头排列) condition2 = (df['ema_short'].iloc[-2] <= df['ema_long'].iloc[-2]) and (df['ema_short'].iloc[-1] > df['ema_long'].iloc[-1]) # 条件3:交易量大于平均值 average_volume = df['volume'].rolling(window=20).mean().iloc[-1] condition3 = latest['volume'] > average_volume # 裸K线策略条件 # 检查趋势(高低点抬高) def is_uptrend(df, periods=20): df_recent = df[-periods:] lows = df_recent['low'] highs = df_recent['high'] trend = all(lows.iloc[i] > lows.iloc[i - 1] and highs.iloc[i] > highs.iloc[i - 1] for i in range(1, len(df_recent))) return trend # 检查看涨吞没形态 def is_bullish_engulfing(df): prev_candle = df.iloc[-2] latest_candle = df.iloc[-1] # 前一根是阴线,当前是阳线 condition_a = prev_candle['close'] < prev_candle['open'] and latest_candle['close'] > latest_candle['open'] # 当前K线的实体完全包住前一根K线的实体 condition_b = latest_candle['close'] > prev_candle['open'] and latest_candle['open'] < prev_candle['close'] return condition_a and condition_b # 检查锤子线形态 def is_hammer(df): latest_candle = df.iloc[-1] body = abs(latest_candle['close'] - latest_candle['open']) lower_wick = min(latest_candle['open'], latest_candle['close']) - latest_candle['low'] upper_wick = latest_candle['high'] - max(latest_candle['open'], latest_candle['close']) # 实体较小,下影线较长,上影线较短 return lower_wick > 2 * body and upper_wick < body condition4 = is_uptrend(df, periods=20) and (is_bullish_engulfing(df) or is_hammer(df))

策略条件我需要改成:
1.最近的6个sma均线(sma 30 sma50 sma100) 呈现多头趋势,或者空头趋势
2.最近的6个k线在sma30 的上方,交叉,下方,这三种情况分别列出来,并且邮件告诉我
3.重新优化下邮件发送的内容,尽量详细又明了,让我知道现在是多头趋势,还是空头趋势,然后最近的k线状态

其他的部分基本不用变化

विचार

Updating script details

I’m thinking about refining the script by removing df = df.iloc[:-1] and updating the strategy conditions to track recent 6 periods of SMA moving averages and K-lines.

Modifying the code

I’m gathering info on where code tweaks are needed, then adjusting conditions, email content, and ensuring smooth overall operation.

उत्तर

好的,让我们按照您的要求一步一步地修改脚本,并确保解释清楚每个修改步骤。


1. 删除剔除最新未完成K线的步骤

您提到这一步不再需要:

python
# 剔除最新的未完成K线 df = df.iloc[:-1]

解释:

  • 这行代码的作用是删除DataFrame中的最后一行,以避免使用未完成的最新K线数据。
  • 您现在希望包括最新的K线数据,因此我们可以删除这行代码。

2. 修改策略条件

您希望将策略条件修改为:

  1. 最近6根SMA均线(SMA30、SMA50、SMA100)呈现多头趋势或空头趋势。
  2. 最近6根K线相对于SMA30的位置(上方、交叉、下方),并分别列出这三种情况,邮件中通知您。
  3. 重新优化邮件内容,使其详细且明了,告诉您现在是多头趋势还是空头趋势,以及最近K线的状态。

2.1 计算SMA指标

首先,我们需要计算SMA30、SMA50、SMA100指标。修改以下代码:

python
from ta.trend import SMAIndicator # 计算SMA指标 df['sma_30'] = SMAIndicator(df['close'], window=30).sma_indicator() df['sma_50'] = SMAIndicator(df['close'], window=50).sma_indicator() df['sma_100'] = SMAIndicator(df['close'], window=100).sma_indicator()

确保在代码顶部导入SMAIndicator

python
from ta.trend import EMAIndicator, SMAIndicator

2.2 定义趋势判断函数

我们需要定义一个函数,判断最近6个周期的SMA均线是否呈现多头趋势或空头趋势。

python
# 判断SMA均线的趋势 def check_sma_trend(df, sma_column, periods=6): sma_values = df[sma_column].iloc[-periods:] # 如果SMA均线持续上升,则为多头趋势;持续下降,则为空头趋势 is_uptrend = all(sma_values.iloc[i] > sma_values.iloc[i - 1] for i in range(1, periods)) is_downtrend = all(sma_values.iloc[i] < sma_values.iloc[i - 1] for i in range(1, periods)) if is_uptrend: return '多头趋势' elif is_downtrend: return '空头趋势' else: return '震荡趋势'

2.3 判断K线相对于SMA30的位置

定义一个函数,判断最近6根K线是位于SMA30的上方、交叉还是下方。

python
# 判断K线相对于SMA30的位置 def check_kline_position(df, periods=6): positions = [] for i in range(-periods, 0): close = df['close'].iloc[i] sma_30 = df['sma_30'].iloc[i] if close > sma_30: positions.append('上方') elif close < sma_30: positions.append('下方') else: positions.append('交叉') # 统计出现次数最多的情况 position_counts = pd.Series(positions).value_counts() dominant_position = position_counts.idxmax() return dominant_position

2.4 修改策略条件的判断

在分析每个时间框架的循环中,替换原有的条件判断部分:

python
# 获取最新的完整K线数据(由于您不再剔除最新K线,这里直接使用最新数据) latest = df.iloc[-1] # 判断SMA均线的趋势 sma_30_trend = check_sma_trend(df, 'sma_30', periods=6) sma_50_trend = check_sma_trend(df, 'sma_50', periods=6) sma_100_trend = check_sma_trend(df, 'sma_100', periods=6) # 判断K线相对于SMA30的位置 kline_position = check_kline_position(df, periods=6) # 汇总趋势信息 sma_trend_info = f"SMA30:{sma_30_trend},SMA50:{sma_50_trend},SMA100:{sma_100_trend}" kline_position_info = f"最近6根K线位于SMA30的{kline_position}" # 将趋势信息和K线位置记录下来 conditions_met = [] conditions_met.append(sma_trend_info) conditions_met.append(kline_position_info)

2.5 更新选币结果的记录

在满足条件的情况下,将趋势信息添加到selected_coins列表中:

python
if True: # 这里不再需要条件判断,因为您希望所有币种都记录趋势信息 print(f"{symbol}{timeframe} 时间框架上的分析结果:{sma_trend_info}{kline_position_info}") logging.info(f"{symbol}{timeframe} 时间框架上的分析结果:{sma_trend_info}{kline_position_info}") timeframes_results.append({ 'timeframe': timeframe, 'sma_trend_info': sma_trend_info, 'kline_position_info': kline_position_info, 'latest': latest # 保存最新的K线数据 })

由于您不再有特定的筛选条件,而是希望记录所有币种的趋势信息,因此我们可以在满足条件的判断中直接通过。

2.6 更新满足时间框架数量的判断

您之前的代码是根据满足条件的时间框架数量进行筛选。由于现在您希望所有币种都记录趋势信息,我们可以调整这部分代码,让它记录所有分析结果。

python
# 汇总符合条件的时间框架和信息 timeframes_info = '; '.join([f"{res['timeframe']}{res['sma_trend_info']}{res['kline_position_info']}" for res in timeframes_results]) print(f"{symbol} 的分析结果已记录。") logging.info(f"{symbol} 的分析结果已记录。") # 获取最新的K线数据(以最后一个时间框架的数据为准,也可以选择其他方式) latest = timeframes_results[-1]['latest'] selected_coins.append({ '币种': symbol, '最新价格': latest['close'], '交易量': latest['volume'], 'SMA30': latest['sma_30'], 'SMA50': latest['sma_50'], 'SMA100': latest['sma_100'], '分析结果': timeframes_info })

3. 优化邮件内容

您希望邮件内容详细且明了,告诉您是多头趋势还是空头趋势,以及最近K线的状态。

3.1 更新DataFrame

在准备发送邮件前,调整df_selected,确保包含新的列:

python
# 将数值格式化(可选) df_selected['最新价格'] = df_selected['最新价格'].apply(lambda x: f"{x:.6f}") df_selected['交易量'] = df_selected['交易量'].apply(lambda x: f"{x:.2f}") df_selected['SMA30'] = df_selected['SMA30'].apply(lambda x: f"{x:.6f}") df_selected['SMA50'] = df_selected['SMA50'].apply(lambda x: f"{x:.6f}") df_selected['SMA100'] = df_selected['SMA100'].apply(lambda x: f"{x:.6f}") # 重新排列列的顺序(可选) df_selected = df_selected[['币种', '最新价格', '交易量', 'SMA30', 'SMA50', 'SMA100', '分析结果']]

3.2 更新邮件正文

调整邮件正文,使其包含趋势信息和K线位置:

python
# 将数据转换为HTML表格 df_email = df_selected[['币种', '最新价格', '交易量', '分析结果']] df_email_html = df_email.to_html(index=False, escape=False) # 邮件正文,使用HTML格式 body = f"""<p>您好,</p> <p>请查收最新的币种分析结果。</p> <p>当前时间:{current_time}</p> <p>分析依据:</p> <ul> <li>趋势判断:最近6个周期的SMA30、SMA50、SMA100均线的走势。</li> <li>K线位置:最近6根K线相对于SMA30的位置(上方、交叉、下方)。</li> </ul> {df_email_html} <p>此致<br/>敬礼</p> """

注意,在to_html中添加参数escape=False,以防止HTML字符被转义,确保邮件中的表格显示正确。


4. 整合修改后的代码

为了便于您查看,我们将完整的修改部分代码整合如下:

4.1 导入SMAIndicator

python
from ta.trend import EMAIndicator, SMAIndicator

4.2 删除剔除最新未完成K线的步骤

python
# df = df.iloc[:-1] # 不再需要这行代码

4.3 在计算指标的部分,添加SMA计算

python
# 计算SMA指标 df['sma_30'] = SMAIndicator(df['close'], window=30).sma_indicator() df['sma_50'] = SMAIndicator(df['close'], window=50).sma_indicator() df['sma_100'] = SMAIndicator(df['close'], window=100).sma_indicator()

4.4 定义趋势判断和K线位置判断函数

python
def check_sma_trend(df, sma_column, periods=6): sma_values = df[sma_column].iloc[-periods:] is_uptrend = all(sma_values.iloc[i] > sma_values.iloc[i - 1] for i in range(1, periods)) is_downtrend = all(sma_values.iloc[i] < sma_values.iloc[i - 1] for i in range(1, periods)) if is_uptrend: return '多头趋势' elif is_downtrend: return '空头趋势' else: return '震荡趋势' def check_kline_position(df, periods=6): positions = [] for i in range(-periods, 0): close = df['close'].iloc[i] sma_30 = df['sma_30'].iloc[i] if close > sma_30: positions.append('上方') elif close < sma_30: positions.append('下方') else: positions.append('交叉') position_counts = pd.Series(positions).value_counts() dominant_position = position_counts.idxmax() return dominant_position

4.5 修改策略条件判断

python
# 获取最新的K线数据 latest = df.iloc[-1] # 判断SMA均线的趋势 sma_30_trend = check_sma_trend(df, 'sma_30', periods=6) sma_50_trend = check_sma_trend(df, 'sma_50', periods=6) sma_100_trend = check_sma_trend(df, 'sma_100', periods=6) # 判断K线相对于SMA30的位置 kline_position = check_kline_position(df, periods=6) # 汇总趋势信息 sma_trend_info = f"SMA30:{sma_30_trend},SMA50:{sma_50_trend},SMA100:{sma_100_trend}" kline_position_info = f"最近6根K线位于SMA30的{kline_position}" # 将趋势信息记录下来 conditions_met = [] conditions_met.append(sma_trend_info) conditions_met.append(kline_position_info) print(f"{symbol}{timeframe} 时间框架上的分析结果:{sma_trend_info}{kline_position_info}") logging.info(f"{symbol}{timeframe} 时间框架上的分析结果:{sma_trend_info}{kline_position_info}") timeframes_results.append({ 'timeframe': timeframe, 'sma_trend_info': sma_trend_info, 'kline_position_info': kline_position_info, 'latest': latest })

4.6 更新选币结果的记录

python
# 汇总符合条件的时间框架和信息 timeframes_info = '; '.join([f"{res['timeframe']}{res['sma_trend_info']}{res['kline_position_info']}" for res in timeframes_results]) print(f"{symbol} 的分析结果已记录。") logging.info(f"{symbol} 的分析结果已记录。") # 获取最新的K线数据 latest = timeframes_results[-1]['latest'] selected_coins.append({ '币种': symbol, '最新价格': latest['close'], '交易量': latest['volume'], 'SMA30': latest['sma_30'], 'SMA50': latest['sma_50'], 'SMA100': latest['sma_100'], '分析结果': timeframes_info })

4.7 优化邮件内容

python
# 将数据转换为HTML表格 df_email = df_selected[['币种', '最新价格', '交易量', '分析结果']] df_email_html = df_email.to_html(index=False, escape=False) # 邮件正文 body = f"""<p>您好,</p> <p>请查收最新的币种分析结果。</p> <p>当前时间:{current_time}</p> <p>分析依据:</p> <ul> <li>趋势判断:最近6个周期的SMA30、SMA50、SMA100均线的走势。</li> <li>K线位置:最近6根K线相对于SMA30的位置(上方、交叉、下方)。</li> </ul> {df_email_html} <p>此致<br/>敬礼</p> """

5. 注意事项

  • 数据量调整:由于计算SMA100需要至少100个数据点,您需要确保fetch_ohlcv函数的limit参数足够大。例如:

    python
    limit = max(100, 6) + 50 # 确保有足够的数据
  • 多时间框架处理:如果您希望在多个时间框架上进行分析,并在邮件中分别展示,可以保留原有的时间框架循环。

  • 邮件发送频率:根据您的需求,您可以调整脚本的运行频率,以便及时获取最新的分析结果。

  • 日志记录:确保日志记录在修改后仍能正常工作,以便于后续的调试和维护。


6. 完整性检查

请确保在修改完脚本后,进行测试以验证:

  • 指标计算是否正确。
  • 趋势判断和K线位置判断是否符合预期。
  • 邮件内容是否包含所需的信息,并且格式正确。

如果在测试过程中遇到任何问题,请及时调整相应的代码。


希望以上修改和解释对您有帮助。如果您有任何疑问或需要进一步的协助,请随时告诉我!

प्रश्न

我看了你的回答,有几个问题还需要优化
1.判断最近6个周期的SMA均线是否呈现多头趋势或空头趋势。我看你是通过判断sma均线持续上升,同时还需要有个条件,多头趋势是sma30大于sma50大于sam10;空头趋势时sma30小于sma50小于sma100
2.断K线相对于SMA30的位置
定义一个函数,判断最近6根K线是位于SMA30的上方、交叉还是下方。这是k线时判断当时k线的sma值吧
3.由于您不再有特定的筛选条件,而是希望记录所有币种的趋势信息,因此我们可以在满足条件的判断中直接通过。不是不筛选了,筛选条件是:近6个周期的SMA均线是否呈现多头趋势或空头趋势
4、邮件内容需要帮我模拟下,我想能直观看到当前趋势和k线的相对位置

विचार

Clarifying the trend conditions

I’m noting that for a bullish trend, the SMA values should be ordered correctly (SMA30 > SMA50 > SMA100), and similarly for a bearish trend (SMA30 < SMA50 < SMA100).

Refining trend determination

I’m honing in on trend determination, factoring in that SMA values must consistently rise or fall over the last 6 periods, with specific conditions like SMA30 > SMA50 > SMA100 for bullish or SMA30 < SMA50 < SMA100 for bearish trends.

Clarifying the trend evaluation

I’m outlining that the function determines trends by analyzing the SMA values over the last 6 periods and ensures the SMA lines are in the correct bullish or bearish order at the latest time point.

Optimizing email content

I'm updating email content to clearly show current trends and K-lines' positions. Also, I’ll simulate an example to enhance visual clarity and pertinent updates.

改进趋势判断

我正在优化check_sma_trend函数,以便同时考虑SMA均线的趋势和相对位置,以准确识别多头、空头或震荡趋势。

筛选和发送分析

我正在筛选符合多头或空头趋势的时间框架币种,生成邮件内容并将数据转换为HTML表格,以便准确显示分析结果。

分析币种趋势

我更新了趋势判断函数,分析近6个周期的SMA均线走势,判断多头、空头或震荡趋势。仅在明确趋势时继续处理K线位置。

उत्तर

好的,我理解了您的要求,接下来我将针对您提到的几点进行优化和修改。

1. 优化SMA均线趋势的判断

您希望在判断最近6个周期的SMA均线趋势时,不仅要判断SMA均线是否持续上升或下降,还要满足以下条件:

  • 多头趋势:SMA30 > SMA50 > SMA100
  • 空头趋势:SMA30 < SMA50 < SMA100

修改趋势判断函数

我们需要修改check_sma_trend函数,使其包含这两个条件。

python
def check_sma_trend(df, periods=6): # 获取最近periods周期的SMA值 sma_30_values = df['sma_30'].iloc[-periods:] sma_50_values = df['sma_50'].iloc[-periods:] sma_100_values = df['sma_100'].iloc[-periods:] # 判断SMA均线是否持续上升或下降 sma_30_up = all(sma_30_values.iloc[i] > sma_30_values.iloc[i - 1] for i in range(1, periods)) sma_50_up = all(sma_50_values.iloc[i] > sma_50_values.iloc[i - 1] for i in range(1, periods)) sma_100_up = all(sma_100_values.iloc[i] > sma_100_values.iloc[i - 1] for i in range(1, periods)) sma_30_down = all(sma_30_values.iloc[i] < sma_30_values.iloc[i - 1] for i in range(1, periods)) sma_50_down = all(sma_50_values.iloc[i] < sma_50_values.iloc[i - 1] for i in range(1, periods)) sma_100_down = all(sma_100_values.iloc[i] < sma_100_values.iloc[i - 1] for i in range(1, periods)) # 判断最新一周期的SMA均线的相对位置 latest_sma_30 = sma_30_values.iloc[-1] latest_sma_50 = sma_50_values.iloc[-1] latest_sma_100 = sma_100_values.iloc[-1] # 判断多头趋势 if (sma_30_up and sma_50_up and sma_100_up and latest_sma_30 > latest_sma_50 > latest_sma_100): return '多头趋势' # 判断空头趋势 elif (sma_30_down and sma_50_down and sma_100_down and latest_sma_30 < latest_sma_50 < latest_sma_100): return '空头趋势' else: return '震荡趋势'

这样,我们的趋势判断函数就同时考虑了SMA均线的走势和相对位置。

2. 优化K线相对于SMA30的位置判断

您希望确保函数正确地判断最近6根K线相对于SMA30的位置。

修改K线位置判断函数

python
def check_kline_position(df, periods=6): positions = [] for i in range(-periods, 0): close = df['close'].iloc[i] sma_30 = df['sma_30'].iloc[i] if close > sma_30: positions.append('上方') elif close < sma_30: positions.append('下方') else: positions.append('交叉') # 统计出现次数最多的情况 position_counts = pd.Series(positions).value_counts() dominant_position = position_counts.idxmax() return dominant_position

这个函数会遍历最近6根K线,判断每根K线的收盘价相对于当期的SMA30的位置,然后统计最常出现的位置。

3. 恢复筛选条件

您强调筛选条件仍然存在,即近6个周期的SMA均线必须呈现多头趋势或空头趋势

在策略条件判断中添加筛选条件

在分析每个时间框架时,我们需要根据趋势判断的结果来决定是否选取该币种。

python
# 获取最新的K线数据 latest = df.iloc[-1] # 判断SMA均线的趋势 sma_trend = check_sma_trend(df, periods=6) # 仅当趋势为多头或空头时,才继续处理 if sma_trend in ['多头趋势', '空头趋势']: # 判断K线相对于SMA30的位置 kline_position = check_kline_position(df, periods=6) # 汇总趋势信息 sma_trend_info = f"趋势:{sma_trend}" kline_position_info = f"最近6根K线位于SMA30的{kline_position}" print(f"{symbol}{timeframe} 时间框架上的分析结果:{sma_trend_info}{kline_position_info}") logging.info(f"{symbol}{timeframe} 时间框架上的分析结果:{sma_trend_info}{kline_position_info}") timeframes_results.append({ 'timeframe': timeframe, 'sma_trend_info': sma_trend_info, 'kline_position_info': kline_position_info, 'latest': latest }) else: print(f"{symbol}{timeframe} 时间框架上为震荡趋势,跳过。") logging.info(f"{symbol}{timeframe} 时间框架上为震荡趋势,跳过。")

这样,我们就只会记录那些在指定时间框架上呈现多头或空头趋势的币种。

筛选满足条件的币种

继续使用之前的逻辑,筛选在足够多的时间框架上满足条件的币种。

python
# 筛选满足条件的时间框架数量 timeframes_required = config.timeframes_required if len(timeframes_results) >= timeframes_required: # 汇总符合条件的时间框架和信息 timeframes_info = '; '.join([f"{res['timeframe']}{res['sma_trend_info']}{res['kline_position_info']}" for res in timeframes_results]) print(f"{symbol} 在至少 {timeframes_required} 个时间框架上符合条件,加入列表。") logging.info(f"{symbol} 在至少 {timeframes_required} 个时间框架上符合条件,加入列表。") # 获取最新的K线数据 latest = timeframes_results[-1]['latest'] selected_coins.append({ '币种': symbol, '最新价格': latest['close'], '交易量': latest['volume'], 'SMA30': latest['sma_30'], 'SMA50': latest['sma_50'], 'SMA100': latest['sma_100'], '分析结果': timeframes_info }) else: print(f"{symbol} 在满足条件的时间框架数量不足,跳过。") logging.info(f"{symbol} 在满足条件的时间框架数量不足,跳过。")

4. 优化邮件内容

您希望邮件内容能够直观地展示当前趋势和K线的相对位置。

模拟邮件内容

假设我们有以下选币结果:

python
df_email = df_selected[['币种', '最新价格', '交易量', '分析结果']]
邮件正文示例
html
<p>您好,</p> <p>请查收最新的币种分析结果。</p> <p>当前时间:2023-10-10 12:00:00</p> <p>分析依据:</p> <ul> <li>趋势判断:近6个周期的SMA30、SMA50、SMA100均线走势及相对位置。</li> <li>K线位置:最近6根K线相对于SMA30的位置(上方、交叉、下方)。</li> </ul> <table> <thead> <tr> <th>币种</th> <th>最新价格</th> <th>交易量</th> <th>分析结果</th> </tr> </thead> <tbody> <tr> <td>BTC/USDT</td> <td>50000.00</td> <td>1000000.00</td> <td>1h:趋势:多头趋势,最近6根K线位于SMA30的上方;<br>4h:趋势:多头趋势,最近6根K线位于SMA30的上方</td> </tr> <tr> <td>ETH/USDT</td> <td>3500.00</td> <td>800000.00</td> <td>1h:趋势:空头趋势,最近6根K线位于SMA30的下方;<br>4h:趋势:空头趋势,最近6根K线位于SMA30的下方</td> </tr> </tbody> </table> <p>此致<br/>敬礼</p>

在代码中生成邮件内容

python
# 将数据转换为HTML表格 df_email = df_selected[['币种', '最新价格', '交易量', '分析结果']] # 将分析结果中的'; '替换为'<br>',以在邮件中正确显示换行 df_email['分析结果'] = df_email['分析结果'].apply(lambda x: x.replace('; ', '<br>')) # 转换为HTML表格 df_email_html = df_email.to_html(index=False, escape=False) # 邮件正文 body = f"""<p>您好,</p> <p>请查收最新的币种分析结果。</p> <p>当前时间:{current_time}</p> <p>分析依据:</p> <ul> <li>趋势判断:近6个周期的SMA30、SMA50、SMA100均线走势及相对位置。</li> <li>K线位置:最近6根K线相对于SMA30的位置(上方、交叉、下方)。</li> </ul> {df_email_html} <p>此致<br/>敬礼</p> """

确保邮件内容清晰直观

  • 分析结果列中包含多个时间框架的分析,使用<br>标签分隔,便于阅读。
  • 表格清晰地展示币种、最新价格、交易量和分析结果。

5. 整合修改后的代码

将上述修改整合到脚本中。

5.1 更新趋势判断函数

python
def check_sma_trend(df, periods=6): # 获取最近periods周期的SMA值 sma_30_values = df['sma_30'].iloc[-periods:] sma_50_values = df['sma_50'].iloc[-periods:] sma_100_values = df['sma_100'].iloc[-periods:] # 判断SMA均线是否持续上升或下降 sma_30_up = all(sma_30_values.iloc[i] > sma_30_values.iloc[i - 1] for i in range(1, periods)) sma_50_up = all(sma_50_values.iloc[i] > sma_50_values.iloc[i - 1] for i in range(1, periods)) sma_100_up = all(sma_100_values.iloc[i] > sma_100_values.iloc[i - 1] for i in range(1, periods)) sma_30_down = all(sma_30_values.iloc[i] < sma_30_values.iloc[i - 1] for i in range(1, periods)) sma_50_down = all(sma_50_values.iloc[i] < sma_50_values.iloc[i - 1] for i in range(1, periods)) sma_100_down = all(sma_100_values.iloc[i] < sma_100_values.iloc[i - 1] for i in range(1, periods)) # 判断最新一周期的SMA均线的相对位置 latest_sma_30 = sma_30_values.iloc[-1] latest_sma_50 = sma_50_values.iloc[-1] latest_sma_100 = sma_100_values.iloc[-1] # 判断多头趋势 if (sma_30_up and sma_50_up and sma_100_up and latest_sma_30 > latest_sma_50 > latest_sma_100): return '多头趋势' # 判断空头趋势 elif (sma_30_down and sma_50_down and sma_100_down and latest_sma_30 < latest_sma_50 < latest_sma_100): return '空头趋势' else: return '震荡趋势'

5.2 更新策略条件判断

python
# 获取最新的K线数据 latest = df.iloc[-1] # 判断SMA均线的趋势 sma_trend = check_sma_trend(df, periods=6) # 仅当趋势为多头或空头时,才继续处理 if sma_trend in ['多头趋势', '空头趋势']: # 判断K线相对于SMA30的位置 kline_position = check_kline_position(df, periods=6) # 汇总趋势信息 sma_trend_info = f"趋势:{sma_trend}" kline_position_info = f"最近6根K线位于SMA30的{kline_position}" print(f"{symbol}{timeframe} 时间框架上的分析结果:{sma_trend_info}{kline_position_info}") logging.info(f"{symbol}{timeframe} 时间框架上的分析结果:{sma_trend_info}{kline_position_info}") timeframes_results.append({ 'timeframe': timeframe, 'sma_trend_info': sma_trend_info, 'kline_position_info': kline_position_info, 'latest': latest }) else: print(f"{symbol}{timeframe} 时间框架上为震荡趋势,跳过。") logging.info(f"{symbol}{timeframe} 时间框架上为震荡趋势,跳过。")

5.3 更新邮件内容生成

python
# 将数据转换为HTML表格 df_email = df_selected[['币种', '最新价格', '交易量', '分析结果']] # 替换分析结果中的'; '为'<br>',以在邮件中正确显示换行 df_email['分析结果'] = df_email['分析结果'].apply(lambda x: x.replace('; ', '<br>')) # 转换为HTML表格 df_email_html = df_email.to_html(index=False, escape=False) # 邮件正文 body = f"""<p>您好,</p> <p>请查收最新的币种分析结果。</p> <p>当前时间:{current_time}</p> <p>分析依据:</p> <ul> <li>趋势判断:近6个周期的SMA30、SMA50、SMA100均线走势及相对位置。</li> <li>K线位置:最近6根K线相对于SMA30的位置(上方、交叉、下方)。</li> </ul> {df_email_html} <p>此致<br/>敬礼</p> """

6. 注意事项

  • 数据量:确保获取足够的数据来计算SMA100和最近6个周期的数据。例如,在fetch_ohlcv时,limit参数需要设置为100 + 6甚至更多。

    python
    limit = 100 + 6 + 50 # 计算SMA100需要至少100个数据点,加上6个周期和额外的50个数据点作为缓冲
  • 时间框架:根据您的需求,设置config.timeframesconfig.timeframes_required

  • 测试:在修改完代码后,建议您进行测试,确保功能符合预期。


希望以上优化和修改能够满足您的需求。如有任何疑问或需要进一步的帮助,请随时告诉我!

प्रश्न

还有几个问题,麻烦最后给我完整的代码
1.def check_kline_position(df, periods=6):这个函数会遍历最近6根K线,判断每根K线的收盘价相对于当期的SMA30的位置,然后统计最常出现的位置。 需要改成判断每根k线最低价相对于当期的sma的位置,不需要统计最常出现的位置,而是遍历出来,每根k线都遍历出来,后面邮件要告知我
2.筛选满足条件的币种
继续使用之前的逻辑,筛选在足够多的时间框架上满足条件的币种。
任意一个时间框架上满足就行
3.最后一个,邮件内容是包含所有筛选结果的多个币种信息

विचार

Requesting modifications

The user asks for changes in the function to track each candle's lowest price relative to the SMA, filters coins by specific timeframes, and includes comprehensive coin details in the email.

Revamping the function

I’m reworking the check_kline_position function to assess the lowest price of each of the last 6 candles against the SMA, listing each candle's position for clarity.

Acknowledge and respond

I’ll first acknowledge the user's request, addressing each point with detailed explanations and then provide the complete code with all modifications included.

优化筛选条件

调整筛选币种的条件,确保每个时间框架都有符合条件的币种,并且将所有筛选结果以HTML表格形式发送邮件。

उत्तर

好的,我会按照您的要求进行修改,并在最后提供完整的代码。


1. 修改K线相对于SMA30的位置判断函数

您希望修改check_kline_position函数,使其:

  • 判断每根K线的最低价相对于当期的SMA30的位置。
  • 不统计最常出现的位置,而是遍历每根K线,记录其位置。
  • 在邮件中告知您每根K线的具体位置。

修改后的函数

python
def check_kline_position(df, periods=6): positions = [] for i in range(-periods, 0): low = df['low'].iloc[i] sma_30 = df['sma_30'].iloc[i] timestamp = df.index[i].strftime('%Y-%m-%d %H:%M') if low > sma_30: position = f"第{i + periods + 1}根K线({timestamp}):最低价在SMA30上方" elif low < sma_30: position = f"第{i + periods + 1}根K线({timestamp}):最低价在SMA30下方" else: position = f"第{i + periods + 1}根K线({timestamp}):最低价与SMA30持平" positions.append(position) return positions
  • 使用low代替close,比较最低价和SMA30。
  • 记录每根K线的编号(1到6)和时间戳,便于识别。
  • 返回一个列表,包含每根K线的位置描述。

2. 筛选满足条件的币种

您希望在任意一个时间框架上满足条件的币种就被选中。

修改筛选条件

在判断币种是否加入selected_coins时,我们调整条件:

python
if len(timeframes_results) >= 1: # 汇总符合条件的时间框架和信息 timeframes_info = '<br>'.join([f"{res['timeframe']}{res['sma_trend_info']}<br>{'<br>'.join(res['kline_position_info'])}" for res in timeframes_results]) print(f"{symbol} 在至少一个时间框架上符合条件,加入列表。") logging.info(f"{symbol} 在至少一个时间框架上符合条件,加入列表。") # 获取最新的K线数据 latest = timeframes_results[-1]['latest'] selected_coins.append({ '币种': symbol, '最新价格': latest['close'], '交易量': latest['volume'], 'SMA30': latest['sma_30'], 'SMA50': latest['sma_50'], 'SMA100': latest['sma_100'], '分析结果': timeframes_info }) else: print(f"{symbol} 在任何时间框架上都不符合条件,跳过。") logging.info(f"{symbol} 在任何时间框架上都不符合条件,跳过。")
  • len(timeframes_results) >= timeframes_required修改为len(timeframes_results) >= 1
  • timeframes_info中,包含每个时间框架的kline_position_info,并用<br>分隔,便于在邮件中显示。

3. 邮件内容包含所有筛选结果的多个币种信息

确保邮件中包含所有筛选出的币种信息,格式清晰,便于阅读。

调整邮件内容

python
# 将数据转换为HTML表格 df_email = df_selected[['币种', '最新价格', '交易量', '分析结果']] # 不转义HTML字符,确保格式正确 df_email_html = df_email.to_html(index=False, escape=False) # 邮件正文 body = f"""<p>您好,</p> <p>请查收最新的币种分析结果。</p> <p>当前时间:{current_time}</p> <p>分析依据:</p> <ul> <li>趋势判断:近6个周期的SMA30、SMA50、SMA100均线走势及相对位置。</li> <li>K线位置:最近6根K线的最低价相对于SMA30的位置。</li> </ul> {df_email_html} <p>此致<br/>敬礼</p> """
  • 确保df_email['分析结果']中的内容已经正确格式化,包含了每根K线的位置。

4. 完整代码

下面是根据您的要求修改后的完整代码:

python
import sys # 设置事件循环策略,解决Windows上的事件循环问题 if sys.platform.startswith('win'): import asyncio asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) import ccxt.async_support as ccxt # 使用异步版本的ccxt import pandas as pd import datetime import smtplib import config import os from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart import asyncio from ta.trend import EMAIndicator, SMAIndicator import logging # 配置日志记录 script_dir = os.path.dirname(os.path.abspath(__file__)) log_folder = os.path.join(script_dir, 'logs') if not os.path.exists(log_folder): os.makedirs(log_folder) log_filename = os.path.join(log_folder, f"log_{datetime.datetime.now().strftime('%Y%m%d')}.log") logging.basicConfig(filename=log_filename, level=logging.INFO, format='%(asctime)s %(levelname)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S') # 1. 使用ccxt库连接MEXC交易所 print("正在连接到 MEXC 交易所...") logging.info("正在连接到 MEXC 交易所...") async def main(): # 初始化交易所连接 print("正在初始化交易所连接...") logging.info("正在初始化交易所连接...") exchange = ccxt.mexc({ 'apiKey': config.apiKey, 'secret': config.secret, 'password': config.password, 'enableRateLimit': True, 'timeout': 60000, 'aiohttp_proxy': config.proxy, # 设置异步模式下的代理 }) # 2. 获取所有合约币种 print("正在获取所有合约币种...") logging.info("正在获取所有合约币种...") await exchange.load_markets() symbols = [market['symbol'] for market in exchange.markets.values() if market['active'] and market['type'] == 'swap'] print(f"共获取到 {len(symbols)} 个合约币种。") logging.info(f"共获取到 {len(symbols)} 个合约币种。") # 3. 获取这些币种的上一天K线数据,并筛选出交易量前100的币种 print("正在获取上一天K线数据并筛选交易量前100的币种...") logging.info("正在获取上一天K线数据并筛选交易量前100的币种...") data_list = [] semaphore = asyncio.Semaphore(config.max_concurrency) # 控制并发数量 async def fetch_volume(symbol): async with semaphore: try: # 获取上一天的1天K线数据(limit=2,取前一天完整的K线) ohlcv = await exchange.fetch_ohlcv(symbol, timeframe='1d', limit=2) if len(ohlcv) >= 2: # 前一天的K线 previous_candle = ohlcv[-2] volume = previous_candle[5] data_list.append({ 'symbol': symbol, 'volume': volume }) print(f"{symbol} 数据获取成功,交易量:{volume}") logging.info(f"{symbol} 数据获取成功,交易量:{volume}") else: print(f"{symbol} 无足够的K线数据。") logging.warning(f"{symbol} 无足够的K线数据。") except Exception as e: print(f"获取 {symbol} 数据时出错:{e}") logging.error(f"获取 {symbol} 数据时出错:{e}") tasks = [asyncio.ensure_future(fetch_volume(symbol)) for symbol in symbols] await asyncio.gather(*tasks) # 关闭交易所连接 await exchange.close() # 筛选交易量前100的币种 df_volume = pd.DataFrame(data_list) df_volume = df_volume.sort_values(by='volume', ascending=False) top_symbols = df_volume.head(config.top_volume_limit)['symbol'].tolist() print(f"筛选出交易量前{config.top_volume_limit}的币种,共 {len(top_symbols)} 个。") logging.info(f"筛选出交易量前{config.top_volume_limit}的币种,共 {len(top_symbols)} 个。") # 4. 在不同时间框架上计算技术指标并筛选符合条件的币种 print("正在计算技术指标并进行多时间框架分析...") logging.info("正在计算技术指标并进行多时间框架分析...") exchange = ccxt.mexc({ 'apiKey': config.apiKey, 'secret': config.secret, 'password': config.password, 'enableRateLimit': True, 'timeout': 60000, 'aiohttp_proxy': config.proxy, }) selected_coins = [] semaphore = asyncio.Semaphore(config.max_concurrency) # 控制并发数量 async def analyze_symbol(symbol): async with semaphore: try: # 存储不同时间框架的分析结果 timeframes_results = [] for timeframe in config.timeframes: print(f"获取 {symbol}{timeframe} 时间框架的K线数据...") logging.info(f"获取 {symbol}{timeframe} 时间框架的K线数据...") limit = 100 + 6 + 50 # 确保有足够的数据 ohlcv = await exchange.fetch_ohlcv(symbol, timeframe=timeframe, limit=limit) if len(ohlcv) < limit: print(f"{symbol}{timeframe} 时间框架的数据不足,跳过。") logging.warning(f"{symbol}{timeframe} 时间框架的数据不足,跳过。") continue # 将数据转换为DataFrame df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume']) df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms') df.set_index('timestamp', inplace=True) # 计算SMA指标 df['sma_30'] = SMAIndicator(df['close'], window=30).sma_indicator() df['sma_50'] = SMAIndicator(df['close'], window=50).sma_indicator() df['sma_100'] = SMAIndicator(df['close'], window=100).sma_indicator() # 获取最新的K线数据 latest = df.iloc[-1] # 判断SMA均线的趋势 sma_trend = check_sma_trend(df, periods=6) # 仅当趋势为多头或空头时,才继续处理 if sma_trend in ['多头趋势', '空头趋势']: # 判断K线相对于SMA30的位置 kline_positions = check_kline_position(df, periods=6) # 汇总趋势信息 sma_trend_info = f"趋势:{sma_trend}" kline_position_info = kline_positions print(f"{symbol}{timeframe} 时间框架上的分析结果:{sma_trend_info}") logging.info(f"{symbol}{timeframe} 时间框架上的分析结果:{sma_trend_info}") timeframes_results.append({ 'timeframe': timeframe, 'sma_trend_info': sma_trend_info, 'kline_position_info': kline_position_info, 'latest': latest }) else: print(f"{symbol}{timeframe} 时间框架上为震荡趋势,跳过。") logging.info(f"{symbol}{timeframe} 时间框架上为震荡趋势,跳过。") # 控制请求频率 await asyncio.sleep(exchange.rateLimit / 1000) # 筛选满足条件的币种 if len(timeframes_results) >= 1: # 汇总符合条件的时间框架和信息 timeframes_info = '<br>'.join([f"{res['timeframe']}{res['sma_trend_info']}<br>{'<br>'.join(res['kline_position_info'])}" for res in timeframes_results]) print(f"{symbol} 在至少一个时间框架上符合条件,加入列表。") logging.info(f"{symbol} 在至少一个时间框架上符合条件,加入列表。") # 获取最新的K线数据 latest = timeframes_results[-1]['latest'] selected_coins.append({ '币种': symbol, '最新价格': latest['close'], '交易量': latest['volume'], 'SMA30': latest['sma_30'], 'SMA50': latest['sma_50'], 'SMA100': latest['sma_100'], '分析结果': timeframes_info }) else: print(f"{symbol} 在任何时间框架上都不符合条件,跳过。") logging.info(f"{symbol} 在任何时间框架上都不符合条件,跳过。") except Exception as e: print(f"处理 {symbol} 时出错:{e}") logging.error(f"处理 {symbol} 时出错:{e}") # 定义趋势判断函数 def check_sma_trend(df, periods=6): # 获取最近periods周期的SMA值 sma_30_values = df['sma_30'].iloc[-(periods+1):] sma_50_values = df['sma_50'].iloc[-(periods+1):] sma_100_values = df['sma_100'].iloc[-(periods+1):] # 判断SMA均线是否持续上升或下降 sma_30_up = all(sma_30_values.iloc[i] > sma_30_values.iloc[i - 1] for i in range(1, periods+1)) sma_50_up = all(sma_50_values.iloc[i] > sma_50_values.iloc[i - 1] for i in range(1, periods+1)) sma_100_up = all(sma_100_values.iloc[i] > sma_100_values.iloc[i - 1] for i in range(1, periods+1)) sma_30_down = all(sma_30_values.iloc[i] < sma_30_values.iloc[i - 1] for i in range(1, periods+1)) sma_50_down = all(sma_50_values.iloc[i] < sma_50_values.iloc[i - 1] for i in range(1, periods+1)) sma_100_down = all(sma_100_values.iloc[i] < sma_100_values.iloc[i - 1] for i in range(1, periods+1)) # 判断最新一周期的SMA均线的相对位置 latest_sma_30 = sma_30_values.iloc[-1] latest_sma_50 = sma_50_values.iloc[-1] latest_sma_100 = sma_100_values.iloc[-1] # 判断多头趋势 if (sma_30_up and sma_50_up and sma_100_up and latest_sma_30 > latest_sma_50 > latest_sma_100): return '多头趋势' # 判断空头趋势 elif (sma_30_down and sma_50_down and sma_100_down and latest_sma_30 < latest_sma_50 < latest_sma_100): return '空头趋势' else: return '震荡趋势' # 判断K线相对于SMA30的位置 def check_kline_position(df, periods=6): positions = [] for i in range(-periods, 0): low = df['low'].iloc[i] sma_30 = df['sma_30'].iloc[i] timestamp = df.index[i].strftime('%Y-%m-%d %H:%M') if low > sma_30: position = f"第{i + periods + 1}根K线({timestamp}):最低价在SMA30上方" elif low < sma_30: position = f"第{i + periods + 1}根K线({timestamp}):最低价在SMA30下方" else: position = f"第{i + periods + 1}根K线({timestamp}):最低价与SMA30持平" positions.append(position) return positions tasks = [asyncio.ensure_future(analyze_symbol(symbol)) for symbol in top_symbols] await asyncio.gather(*tasks) # 关闭交易所连接 await exchange.close() # 5. 保存结果并发送邮件通知 if selected_coins: df_selected = pd.DataFrame(selected_coins) current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') # 创建保存CSV文件的文件夹 folder_name = os.path.join(script_dir, 'selected_coins') if not os.path.exists(folder_name): os.makedirs(folder_name) filename = os.path.join(folder_name, f"选币结果_{datetime.datetime.now().strftime('%Y%m%d%H%M%S')}.csv") # 将数值格式化(可选) df_selected['最新价格'] = df_selected['最新价格'].apply(lambda x: f"{x:.6f}") df_selected['交易量'] = df_selected['交易量'].apply(lambda x: f"{x:.2f}") df_selected['SMA30'] = df_selected['SMA30'].apply(lambda x: f"{x:.6f}") df_selected['SMA50'] = df_selected['SMA50'].apply(lambda x: f"{x:.6f}") df_selected['SMA100'] = df_selected['SMA100'].apply(lambda x: f"{x:.6f}") try: df_selected.to_csv(filename, index=False, encoding='utf-8-sig') print(f"选币结果已保存到 {filename}") logging.info(f"选币结果已保存到 {filename}") except Exception as e: print(f"写入文件时出错:{e}") logging.error(f"写入文件时出错:{e}") # 发送邮件通知 print("正在发送邮件...") logging.info("正在发送邮件...") smtp_server = config.smtp_server smtp_port = config.smtp_port sender_email = config.sender_email receiver_email = config.receiver_email password = config.email_password # 请在config.py中使用不同的变量名避免混淆 subject = '选币结果通知' # 将数据转换为HTML表格 df_email = df_selected[['币种', '最新价格', '交易量', '分析结果']] # 不转义HTML字符,确保格式正确 df_email_html = df_email.to_html(index=False, escape=False) # 邮件正文,使用HTML格式 body = f"""<p>您好,</p> <p>请查收最新的币种分析结果。</p> <p>当前时间:{current_time}</p> <p>分析依据:</p> <ul> <li>趋势判断:近6个周期的SMA30、SMA50、SMA100均线走势及相对位置。</li> <li>K线位置:最近6根K线的最低价相对于SMA30的位置。</li> </ul> {df_email_html} <p>此致<br/>敬礼</p> """ # 创建邮件 message = MIMEMultipart() message['From'] = sender_email message['To'] = receiver_email message['Subject'] = subject message.attach(MIMEText(body, 'html', 'utf-8')) try: server = smtplib.SMTP_SSL(smtp_server, smtp_port) server.login(sender_email, password) server.sendmail(sender_email, receiver_email, message.as_string()) server.quit() print("邮件发送成功!") logging.info("邮件发送成功!") except Exception as e: print(f"邮件发送失败:{e}") logging.error(f"邮件发送失败:{e}") else: print("没有符合条件的币种。") logging.info("没有符合条件的币种。") # 运行主函数 if __name__ == "__main__": asyncio.run(main())

请注意:

  • 配置文件config.py:确保您的config.py文件中包含以下参数:

    • apiKey
    • secret
    • password
    • proxy(如果需要)
    • max_concurrency:最大并发数
    • top_volume_limit:交易量前多少的币种
    • timeframes:要分析的时间框架列表(例如['1h', '4h', '1d']
  • 环境依赖:请确保已安装必要的库:

    bash
    pip install ccxt ta pandas
  • 邮件服务器配置:在config.py中正确配置邮件服务器信息:

    • smtp_server
    • smtp_port
    • sender_email
    • receiver_email
    • email_password
  • 日志和结果文件夹:脚本会在当前目录下创建logsselected_coins文件夹,用于保存日志和结果。


希望以上修改和完整代码能满足您的需求。如有任何疑问或需要进一步的帮助,请随时告诉我!

प्रश्न

运行后部分日志如下:
2024-11-27 21:46:04 INFO: DAR/USDT:USDT 在 5m 时间框架上为震荡趋势,跳过。
2024-11-27 21:46:04 INFO: NEIROETH/USDT:USDT 在 1h 时间框架上的分析结果:趋势:空头趋势
2024-11-27 21:46:04 INFO: 获取 DAR/USDT:USDT 在 1h 时间框架的K线数据...
2024-11-27 21:46:04 INFO: 获取 NEIROETH/USDT:USDT 在 2h 时间框架的K线数据...
2024-11-27 21:46:04 INFO: 1INCH/USDT:USDT 在 1h 时间框架上为震荡趋势,跳过。
2024-11-27 21:46:04 INFO: OL/USDT:USDT 在 1h 时间框架上的分析结果:趋势:多头趋势
2024-11-27 21:46:04 INFO: ZIL/USDT:USDT 在 1h 时间框架上为震荡趋势,跳过。
2024-11-27 21:46:04 INFO: WAXP/USDT:USDT 在 5m 时间框架上为震荡趋势,跳过。
2024-11-27 21:46:04 INFO: OP/USDT:USDT 在 5m 时间框架上为震荡趋势,跳过。
2024-11-27 21:46:04 INFO: 获取 1INCH/USDT:USDT 在 2h 时间框架的K线数据...
2024-11-27 21:46:04 INFO: 获取 OL/USDT:USDT 在 2h 时间框架的K线数据...
2024-11-27 21:46:04 INFO: 获取 ZIL/USDT:USDT 在 2h 时间框架的K线数据...
2024-11-27 21:46:04 INFO: 获取 WAXP/USDT:USDT 在 1h 时间框架的K线数据...
2024-11-27 21:46:04 INFO: 获取 OP/USDT:USDT 在 1h 时间框架的K线数据...
2024-11-27 21:46:04 ERROR: 处理 NEIROETH/USDT:USDT 时出错:mexc {"success":false,"code":600,"message":"Param error!"}
2024-11-27 21:46:04 ERROR: 处理 1INCH/USDT:USDT 时出错:mexc {"success":false,"code":600,"message":"Param error!"}
2024-11-27 21:46:05 ERROR: 处理 ZIL/USDT:USDT 时出错:mexc {"success":false,"code":600,"message":"Param error!"}
2024-11-27 21:46:05 ERROR: 处理 OL/USDT:USDT 时出错:mexc {"success":false,"code":600,"message":"Param error!"}
2024-11-27 21:46:05 INFO: WAXP/USDT:USDT 在 1h 时间框架上为震荡趋势,跳过。
2024-11-27 21:46:05 INFO: 获取 WAXP/USDT:USDT 在 2h 时间框架的K线数据...
2024-11-27 21:46:05 INFO: OP/USDT:USDT 在 1h 时间框架上为震荡趋势,跳过。
2024-11-27 21:46:05 INFO: 获取 OP/USDT:USDT 在 2h 时间框架的K线数据...
2024-11-27 21:46:06 ERROR: 处理 WAXP/USDT:USDT 时出错:mexc {"success":false,"code":600,"message":"Param error!"}
2024-11-27 21:46:06 ERROR: 处理 OP/USDT:USDT 时出错:mexc {"success":false,"code":600,"message":"Param error!"}
2024-11-27 21:46:06 INFO: DAR/USDT:USDT 在 1h 时间框架上为震荡趋势,跳过。
2024-11-27 21:46:06 INFO: 获取 DAR/USDT:USDT 在 2h 时间框架的K线数据...
2024-11-27 21:46:06 ERROR: 处理 DAR/USDT:USDT 时出错:mexc {"success":false,"code":600,"message":"Param error!"}
2024-11-27 21:46:07 INFO: 没有符合条件的币种。
有两个问题
1.2024-11-27 21:46:06 ERROR: 处理 DAR/USDT:USDT 时出错:mexc {"success":false,"code":600,"message":"Param error!"}有这种报错
2.2024-11-27 21:46:04 INFO: OL/USDT:USDT 在 1h 时间框架上的分析结果:趋势:多头趋势
有符合趋势的但最后却没有符合条件的币种。只要有多头或者空头趋势其实就是我想要的

विचार

Identifying and resolving issues

I’m tackling two problems: error messages related to parameter issues and the script's failure to identify coins with trending conditions, despite indications of a bull trend for OL/USDT.

Analyzing the issues

I’m piecing together the problem:

  1. The error comes from MEXC API, likely invalid parameters or timeframe.
  2. The script isn't adding coins to selected_coins, so I’ll review the code for possible errors.

Identifying the issue

OK, let me see. I’m piecing together why OL/USDT isn’t included in selected_coins. The issue might involve exception handling, especially around processing at the 2h timeframe, leading to a "Param error!"

Refining error handling

I'm examining the analyze_symbol function to ensure errors in processing one timeframe don't halt progress. Adjusting exception handling will allow the code to proceed and add symbols if any timeframe meets the conditions.

Crafting a solution

I’m piecing together an assistant’s response, suggesting verifying config.timeframes for MEXC exchange and embedding error handling within the timeframe loop.

结合时间框架

我正在查看时间框架的支持情况和参数的有效性,以确保所有的交易符号都能正常处理。解决方法包括检查和修改时间框架,以及添加异常处理逻辑。

उत्तर

尊敬的用户,您好!

针对您提出的两个问题,我将一一进行分析并提供解决方案。


问题1:处理币种时出现 Param error 错误

您在日志中看到如下错误:

2024-11-27 21:46:05 ERROR: 处理 OL/USDT:USDT 时出错:mexc {"success":false,"code":600,"message":"Param error!"}

原因分析:

  • 时间框架不支持:MEXC 交易所可能不支持某些时间框架,例如 2h5m 等。
  • 参数错误:请求中包含了不被交易所认可的参数,导致请求失败。

解决方案:

  1. 检查时间框架是否被交易所支持:

    • 请确认您在 config.timeframes 中指定的时间框架是否被 MEXC 交易所支持。
    • 常见的时间框架有:'1m', '5m', '15m', '30m', '1h', '4h', '1d', '1w'
    • 不同交易所支持的时间框架可能有所不同,建议您参考 ccxt 文档或直接测试。
  2. 修改时间框架列表:

    • 如果某些时间框架不被支持,请从 config.timeframes 中移除这些时间框架。
    • 例如,将时间框架列表修改为仅包含常用且被支持的时间框架,如 ['1h', '4h', '1d']
  3. 添加异常处理,避免单个时间框架的错误中断整个币种的处理:

    • 在处理每个时间框架时,添加 try-except 块,以捕获单个时间框架的错误,而不影响其他时间框架的处理。

问题2:有符合趋势的币种,但最后却没有符合条件的币种

您在日志中看到:

2024-11-27 21:46:04 INFO: OL/USDT:USDT 在 1h 时间框架上的分析结果:趋势:多头趋势

但最终程序提示:

没有符合条件的币种。

原因分析:

  • 由于在处理 OL/USDT 的下一个时间框架(例如 2h)时发生了错误,导致整个 analyze_symbol 函数退出,OL/USDT 没有被添加到 selected_coins 列表中。
  • 因此,尽管在 1h 时间框架上满足条件,但由于后续错误,最终未被选中。

解决方案:

  • 通过在处理每个时间框架时添加异常处理,确保即使某个时间框架出错,也不会影响整个币种的处理。
  • 这样,OL/USDT1h 时间框架上满足条件,即使在其他时间框架上出错,仍然会被添加到 selected_coins

具体修改

1. 修改时间框架列表

首先,确认 MEXC 交易所支持的时间框架。可以通过以下方式获取:

python
exchange = ccxt.mexc() print("支持的时间框架:", exchange.timeframes)

根据输出结果,更新您的 config.timeframes,确保使用的时间框架都是被支持的。

2. 修改 analyze_symbol 函数

在处理每个时间框架时,添加异常处理,以防止单个时间框架的错误影响整个币种的处理。

python
async def analyze_symbol(symbol): async with semaphore: try: # 存储不同时间框架的分析结果 timeframes_results = [] for timeframe in config.timeframes: try: print(f"获取 {symbol}{timeframe} 时间框架的K线数据...") logging.info(f"获取 {symbol}{timeframe} 时间框架的K线数据...") limit = 100 + 6 + 50 # 确保有足够的数据 ohlcv = await exchange.fetch_ohlcv(symbol, timeframe=timeframe, limit=limit) if len(ohlcv) < limit: print(f"{symbol}{timeframe} 时间框架的数据不足,跳过。") logging.warning(f"{symbol}{timeframe} 时间框架的数据不足,跳过。") continue # 数据处理和指标计算 # ... # 判断SMA均线的趋势 sma_trend = check_sma_trend(df, periods=6) # 仅当趋势为多头或空头时,才继续处理 if sma_trend in ['多头趋势', '空头趋势']: # 判断K线相对于SMA30的位置 kline_positions = check_kline_position(df, periods=6) # 汇总趋势信息 sma_trend_info = f"趋势:{sma_trend}" kline_position_info = kline_positions print(f"{symbol}{timeframe} 时间框架上的分析结果:{sma_trend_info}") logging.info(f"{symbol}{timeframe} 时间框架上的分析结果:{sma_trend_info}") timeframes_results.append({ 'timeframe': timeframe, 'sma_trend_info': sma_trend_info, 'kline_position_info': kline_position_info, 'latest': latest }) else: print(f"{symbol}{timeframe} 时间框架上为震荡趋势,跳过。") logging.info(f"{symbol}{timeframe} 时间框架上为震荡趋势,跳过。") # 控制请求频率 await asyncio.sleep(exchange.rateLimit / 1000) except Exception as e: print(f"{symbol}{timeframe} 时间框架处理时出错:{e}") logging.error(f"{symbol}{timeframe} 时间框架处理时出错:{e}") continue # 跳过当前时间框架,继续下一个 # 筛选满足条件的币种 if len(timeframes_results) >= 1: # 汇总符合条件的时间框架和信息 timeframes_info = '<br>'.join([f"{res['timeframe']}{res['sma_trend_info']}<br>{'<br>'.join(res['kline_position_info'])}" for res in timeframes_results]) print(f"{symbol} 在至少一个时间框架上符合条件,加入列表。") logging.info(f"{symbol} 在至少一个时间框架上符合条件,加入列表。") # 获取最新的K线数据 latest = timeframes_results[-1]['latest'] selected_coins.append({ '币种': symbol, '最新价格': latest['close'], '交易量': latest['volume'], 'SMA30': latest['sma_30'], 'SMA50': latest['sma_50'], 'SMA100': latest['sma_100'], '分析结果': timeframes_info }) else: print(f"{symbol} 在任何时间框架上都不符合条件,跳过。") logging.info(f"{symbol} 在任何时间框架上都不符合条件,跳过。") except Exception as e: print(f"处理 {symbol} 时出错:{e}") logging.error(f"处理 {symbol} 时出错:{e}")

说明:

  • 在处理每个时间框架时,添加了 try-except 块,捕获并记录异常,但不会影响其他时间框架的处理。
  • 这样,即使某个时间框架出错,程序仍会继续处理其他时间框架,避免遗漏符合条件的币种。

验证结果

修改代码后,重新运行脚本,观察日志:

  • 如果仍有 Param error 的错误,请确认对应的时间框架是否被支持,并在 config.timeframes 中移除。
  • 查看日志中是否有符合条件的币种被加入 selected_coins
  • 最终,邮件应包含所有符合条件的币种信息。

总结

通过上述修改,可以解决您遇到的问题:

  • 避免了由于单个时间框架的错误导致整个币种处理失败的情况。
  • 确保在至少一个时间框架上符合条件的币种能够被正确选中并包含在邮件中。

如果您在修改后仍然遇到问题,欢迎随时反馈,我会继续协助您解决。

प्रश्न

麻烦给我完整的代码,并且给我加上print("支持的时间框架:", exchange.timeframes)

विचार

Confirming the adjustments I'm noting that the assistant should provide the complete code, including the necessary modifications and the print statement, while adhering to OpenAI policies.

Maintaining clarity

I’m compiling the full code with all suggested modifications, ensuring precision and including the statement to support the specified timeframes.

Summarizing the assistant's role

I’m pulling together to provide the complete code, including the print statement. The code is properly formatted with necessary comments, and additional notes may be included.

Identifying placement

I’m figuring out the ideal spot for the print statement to efficiently display supported timeframes, likely just before using timeframes in the main function.

连接交易所并筛选币种

我正在使用ccxt库连接MEXC交易所,获取支持的时间框架和所有合约币种。接着,获取并筛选出交易量前100的币种。

审核交易数据

正在衡量交易量,评估技术指标,分析监控数据。

判断趋势

我正在分析不同时间框架上的趋势符合程度,并获取最新的K线数据。这让我想到了如何通过复杂的技术分析来增加投资决策的可信度。

Analyzing data and sending notifications

I’m analyzing cryptocurrency data, comparing latest prices to SMA30, and checking trade volumes. If conditions meet, I'm preparing to save and send an email with the results to notify relevant parties.

उत्तर

好的,我已经将完整的代码整理如下,并在代码中添加了您要求的 print("支持的时间框架:", exchange.timeframes) 语句。以下是完整的代码:

python
import sys # 设置事件循环策略,解决Windows上的事件循环问题 if sys.platform.startswith('win'): import asyncio asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) import ccxt.async_support as ccxt # 使用异步版本的ccxt import pandas as pd import datetime import smtplib import config import os from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart import asyncio from ta.trend import EMAIndicator, SMAIndicator import logging # 配置日志记录 script_dir = os.path.dirname(os.path.abspath(__file__)) log_folder = os.path.join(script_dir, 'logs') if not os.path.exists(log_folder): os.makedirs(log_folder) log_filename = os.path.join(log_folder, f"log_{datetime.datetime.now().strftime('%Y%m%d')}.log") logging.basicConfig(filename=log_filename, level=logging.INFO, format='%(asctime)s %(levelname)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S') # 1. 使用ccxt库连接MEXC交易所 print("正在连接到 MEXC 交易所...") logging.info("正在连接到 MEXC 交易所...") async def main(): # 初始化交易所连接 print("正在初始化交易所连接...") logging.info("正在初始化交易所连接...") exchange = ccxt.mexc({ 'apiKey': config.apiKey, 'secret': config.secret, 'password': config.password, 'enableRateLimit': True, 'timeout': 60000, 'aiohttp_proxy': config.proxy, # 设置异步模式下的代理 }) # 打印支持的时间框架 print("支持的时间框架:", exchange.timeframes) logging.info(f"支持的时间框架:{exchange.timeframes}") # 2. 获取所有合约币种 print("正在获取所有合约币种...") logging.info("正在获取所有合约币种...") await exchange.load_markets() symbols = [market['symbol'] for market in exchange.markets.values() if market['active'] and market['type'] == 'swap'] print(f"共获取到 {len(symbols)} 个合约币种。") logging.info(f"共获取到 {len(symbols)} 个合约币种。") # 3. 获取这些币种的上一天K线数据,并筛选出交易量前100的币种 print("正在获取上一天K线数据并筛选交易量前100的币种...") logging.info("正在获取上一天K线数据并筛选交易量前100的币种...") data_list = [] semaphore = asyncio.Semaphore(config.max_concurrency) # 控制并发数量 async def fetch_volume(symbol): async with semaphore: try: # 获取上一天的1天K线数据(limit=2,取前一天完整的K线) ohlcv = await exchange.fetch_ohlcv(symbol, timeframe='1d', limit=2) if len(ohlcv) >= 2: # 前一天的K线 previous_candle = ohlcv[-2] volume = previous_candle[5] data_list.append({ 'symbol': symbol, 'volume': volume }) print(f"{symbol} 数据获取成功,交易量:{volume}") logging.info(f"{symbol} 数据获取成功,交易量:{volume}") else: print(f"{symbol} 无足够的K线数据。") logging.warning(f"{symbol} 无足够的K线数据。") except Exception as e: print(f"获取 {symbol} 数据时出错:{e}") logging.error(f"获取 {symbol} 数据时出错:{e}") tasks = [asyncio.ensure_future(fetch_volume(symbol)) for symbol in symbols] await asyncio.gather(*tasks) # 关闭交易所连接 await exchange.close() # 筛选交易量前100的币种 df_volume = pd.DataFrame(data_list) df_volume = df_volume.sort_values(by='volume', ascending=False) top_symbols = df_volume.head(config.top_volume_limit)['symbol'].tolist() print(f"筛选出交易量前{config.top_volume_limit}的币种,共 {len(top_symbols)} 个。") logging.info(f"筛选出交易量前{config.top_volume_limit}的币种,共 {len(top_symbols)} 个。") # 4. 在不同时间框架上计算技术指标并筛选符合条件的币种 print("正在计算技术指标并进行多时间框架分析...") logging.info("正在计算技术指标并进行多时间框架分析...") exchange = ccxt.mexc({ 'apiKey': config.apiKey, 'secret': config.secret, 'password': config.password, 'enableRateLimit': True, 'timeout': 60000, 'aiohttp_proxy': config.proxy, }) selected_coins = [] semaphore = asyncio.Semaphore(config.max_concurrency) # 控制并发数量 async def analyze_symbol(symbol): async with semaphore: try: # 存储不同时间框架的分析结果 timeframes_results = [] for timeframe in config.timeframes: try: print(f"获取 {symbol}{timeframe} 时间框架的K线数据...") logging.info(f"获取 {symbol}{timeframe} 时间框架的K线数据...") limit = 100 + 6 + 50 # 确保有足够的数据 ohlcv = await exchange.fetch_ohlcv(symbol, timeframe=timeframe, limit=limit) if len(ohlcv) < limit: print(f"{symbol}{timeframe} 时间框架的数据不足,跳过。") logging.warning(f"{symbol}{timeframe} 时间框架的数据不足,跳过。") continue # 将数据转换为DataFrame df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume']) df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms') df.set_index('timestamp', inplace=True) # 计算SMA指标 df['sma_30'] = SMAIndicator(df['close'], window=30).sma_indicator() df['sma_50'] = SMAIndicator(df['close'], window=50).sma_indicator() df['sma_100'] = SMAIndicator(df['close'], window=100).sma_indicator() # 获取最新的K线数据 latest = df.iloc[-1] # 判断SMA均线的趋势 sma_trend = check_sma_trend(df, periods=6) # 仅当趋势为多头或空头时,才继续处理 if sma_trend in ['多头趋势', '空头趋势']: # 判断K线相对于SMA30的位置 kline_positions = check_kline_position(df, periods=6) # 汇总趋势信息 sma_trend_info = f"趋势:{sma_trend}" kline_position_info = kline_positions print(f"{symbol}{timeframe} 时间框架上的分析结果:{sma_trend_info}") logging.info(f"{symbol}{timeframe} 时间框架上的分析结果:{sma_trend_info}") timeframes_results.append({ 'timeframe': timeframe, 'sma_trend_info': sma_trend_info, 'kline_position_info': kline_position_info, 'latest': latest }) else: print(f"{symbol}{timeframe} 时间框架上为震荡趋势,跳过。") logging.info(f"{symbol}{timeframe} 时间框架上为震荡趋势,跳过。") # 控制请求频率 await asyncio.sleep(exchange.rateLimit / 1000) except Exception as e: print(f"{symbol}{timeframe} 时间框架处理时出错:{e}") logging.error(f"{symbol}{timeframe} 时间框架处理时出错:{e}") continue # 跳过当前时间框架,继续下一个 # 筛选满足条件的币种 if len(timeframes_results) >= 1: # 汇总符合条件的时间框架和信息 timeframes_info = '<br>'.join([f"{res['timeframe']}{res['sma_trend_info']}<br>{'<br>'.join(res['kline_position_info'])}" for res in timeframes_results]) print(f"{symbol} 在至少一个时间框架上符合条件,加入列表。") logging.info(f"{symbol} 在至少一个时间框架上符合条件,加入列表。") # 获取最新的K线数据 latest = timeframes_results[-1]['latest'] selected_coins.append({ '币种': symbol, '最新价格': latest['close'], '交易量': latest['volume'], 'SMA30': latest['sma_30'], 'SMA50': latest['sma_50'], 'SMA100': latest['sma_100'], '分析结果': timeframes_info }) else: print(f"{symbol} 在任何时间框架上都不符合条件,跳过。") logging.info(f"{symbol} 在任何时间框架上都不符合条件,跳过。") except Exception as e: print(f"处理 {symbol} 时出错:{e}") logging.error(f"处理 {symbol} 时出错:{e}") # 定义趋势判断函数 def check_sma_trend(df, periods=6): # 获取最近 periods+1 个周期的 SMA 值 sma_30_values = df['sma_30'].iloc[-(periods+1):] sma_50_values = df['sma_50'].iloc[-(periods+1):] sma_100_values = df['sma_100'].iloc[-(periods+1):] # 判断 SMA 均线是否持续上升或下降 sma_30_up = all(sma_30_values.iloc[i] > sma_30_values.iloc[i - 1] for i in range(1, periods+1)) sma_50_up = all(sma_50_values.iloc[i] > sma_50_values.iloc[i - 1] for i in range(1, periods+1)) sma_100_up = all(sma_100_values.iloc[i] > sma_100_values.iloc[i - 1] for i in range(1, periods+1)) sma_30_down = all(sma_30_values.iloc[i] < sma_30_values.iloc[i - 1] for i in range(1, periods+1)) sma_50_down = all(sma_50_values.iloc[i] < sma_50_values.iloc[i - 1] for i in range(1, periods+1)) sma_100_down = all(sma_100_values.iloc[i] < sma_100_values.iloc[i - 1] for i in range(1, periods+1)) # 判断最新一周期的 SMA 均线的相对位置 latest_sma_30 = sma_30_values.iloc[-1] latest_sma_50 = sma_50_values.iloc[-1] latest_sma_100 = sma_100_values.iloc[-1] # 判断多头趋势 if (sma_30_up and sma_50_up and sma_100_up and latest_sma_30 > latest_sma_50 > latest_sma_100): return '多头趋势' # 判断空头趋势 elif (sma_30_down and sma_50_down and sma_100_down and latest_sma_30 < latest_sma_50 < latest_sma_100): return '空头趋势' else: return '震荡趋势' # 判断 K 线相对于 SMA30 的位置 def check_kline_position(df, periods=6): positions = [] for i in range(-periods, 0): low = df['low'].iloc[i] sma_30 = df['sma_30'].iloc[i] timestamp = df.index[i].strftime('%Y-%m-%d %H:%M') if low > sma_30: position = f"第{i + periods + 1}根K线({timestamp}):最低价在SMA30上方" elif low < sma_30: position = f"第{i + periods + 1}根K线({timestamp}):最低价在SMA30下方" else: position = f"第{i + periods + 1}根K线({timestamp}):最低价与SMA30持平" positions.append(position) return positions tasks = [asyncio.ensure_future(analyze_symbol(symbol)) for symbol in top_symbols] await asyncio.gather(*tasks) # 关闭交易所连接 await exchange.close() # 5. 保存结果并发送邮件通知 if selected_coins: df_selected = pd.DataFrame(selected_coins) current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') # 创建保存CSV文件的文件夹 folder_name = os.path.join(script_dir, 'selected_coins') if not os.path.exists(folder_name): os.makedirs(folder_name) filename = os.path.join(folder_name, f"选币结果_{datetime.datetime.now().strftime('%Y%m%d%H%M%S')}.csv") # 将数值格式化(可选) df_selected['最新价格'] = df_selected['最新价格'].apply(lambda x: f"{x:.6f}") df_selected['交易量'] = df_selected['交易量'].apply(lambda x: f"{x:.2f}") df_selected['SMA30'] = df_selected['SMA30'].apply(lambda x: f"{x:.6f}") df_selected['SMA50'] = df_selected['SMA50'].apply(lambda x: f"{x:.6f}") df_selected['SMA100'] = df_selected['SMA100'].apply(lambda x: f"{x:.6f}") try: df_selected.to_csv(filename, index=False, encoding='utf-8-sig') print(f"选币结果已保存到 {filename}") logging.info(f"选币结果已保存到 {filename}") except Exception as e: print(f"写入文件时出错:{e}") logging.error(f"写入文件时出错:{e}") # 发送邮件通知 print("正在发送邮件...") logging.info("正在发送邮件...") smtp_server = config.smtp_server smtp_port = config.smtp_port sender_email = config.sender_email receiver_email = config.receiver_email password = config.email_password # 请在config.py中使用不同的变量名避免混淆 subject = '选币结果通知' # 将数据转换为HTML表格 df_email = df_selected[['币种', '最新价格', '交易量', '分析结果']] # 不转义HTML字符,确保格式正确 df_email_html = df_email.to_html(index=False, escape=False) # 邮件正文,使用HTML格式 body = f"""<p>您好,</p> <p>请查收最新的币种分析结果。</p> <p>当前时间:{current_time}</p> <p>分析依据:</p> <ul> <li>趋势判断:近6个周期的SMA30、SMA50、SMA100均线走势及相对位置。</li> <li>K线位置:最近6根K线的最低价相对于SMA30的位置。</li> </ul> {df_email_html} <p>此致<br/>敬礼</p> """ # 创建邮件 message = MIMEMultipart() message['From'] = sender_email message['To'] = receiver_email message['Subject'] = subject message.attach(MIMEText(body, 'html', 'utf-8')) try: server = smtplib.SMTP_SSL(smtp_server, smtp_port) server.login(sender_email, password) server.sendmail(sender_email, receiver_email, message.as_string()) server.quit() print("邮件发送成功!") logging.info("邮件发送成功!") except Exception as e: print(f"邮件发送失败:{e}") logging.error(f"邮件发送失败:{e}") else: print("没有符合条件的币种。") logging.info("没有符合条件的币种。") # 运行主函数 if __name__ == "__main__": asyncio.run(main())

注意事项:

  1. 添加了打印支持的时间框架语句:

    python
    print("支持的时间框架:", exchange.timeframes) logging.info(f"支持的时间框架:{exchange.timeframes}")

    该语句位于 main() 函数中,初始化交易所连接后立即打印支持的时间框架。这有助于您确认所使用的时间框架是否被交易所支持。

  2. 调整了异常处理:

    • 在处理每个时间框架的数据时,添加了 try-except 块,以捕获并处理可能的异常。
    • 这样,即使某个时间框架不被支持或发生错误,也不会中断整个币种的分析过程。
  3. 修改了筛选条件:

    • 只要在 任意一个时间框架 上满足条件的币种都会被加入 selected_coins 列表。
    • 这样,符合您“只要有多头或者空头趋势就是我想要的”的要求。
  4. 完善了日志和打印信息:

    • 在关键步骤和异常处理中,添加了日志记录和打印输出,方便您在运行时了解程序的执行情况。
  5. 确保邮件内容包含所有筛选结果的多个币种信息:

    • 最终发送的邮件将包含所有符合条件的币种的信息,包括趋势分析和K线位置详情。

建议:

  • 检查 config.py 配置文件: 确保其中的参数(如 apiKeysecretpasswordproxymax_concurrencytop_volume_limittimeframes 等)正确无误。

  • 确认时间框架: 通过打印的支持的时间框架列表,检查并调整您的 config.timeframes,确保其中的时间框架被 MEXC 交易所支持。

  • 安装必要的库: 确保已安装 ccxttapandas 等库。

    bash
    pip install ccxt ta pandas
  • 运行测试: 运行脚本,观察打印输出和日志文件,确认程序按预期执行。如有问题,请根据日志信息进行排查。


如果您在使用过程中有任何问题,欢迎随时告诉我!

इस प्रश्नोत्तर को साझा करें