From 0af8dc562b401ba2be9c92be51324403e51ee280 Mon Sep 17 00:00:00 2001 From: 27942 Date: Sun, 4 Jan 2026 18:24:42 +0800 Subject: [PATCH] fewfef --- bitmart/抓取数据_30分钟.py | 150 ++++++++++++++ models/bitmart.py | 21 ++ models/database.db | Bin 380928 -> 2437120 bytes weex/自动化抓取数据.py | 22 +- weex/长期持有信号/database.db | Bin 8192 -> 0 bytes weex/长期持有信号/读取数据库数据-30分钟版.py | 206 +++++++++++++------ 6 files changed, 323 insertions(+), 76 deletions(-) create mode 100644 bitmart/抓取数据_30分钟.py create mode 100644 models/bitmart.py delete mode 100644 weex/长期持有信号/database.db diff --git a/bitmart/抓取数据_30分钟.py b/bitmart/抓取数据_30分钟.py new file mode 100644 index 0000000..3101693 --- /dev/null +++ b/bitmart/抓取数据_30分钟.py @@ -0,0 +1,150 @@ +""" +BitMart 30分钟K线数据抓取脚本 +从 BitMart API 获取30分钟K线数据并存储到数据库 +""" + +import time +from loguru import logger +from bitmart.api_contract import APIContract +from models.bitmart import BitMart30 + + +class BitMartDataCollector: + def __init__(self): + self.api_key = "a0fb7b98464fd9bcce67e7c519d58ec10d0c38a8" + self.secret_key = "4eaeba78e77aeaab1c2027f846a276d164f264a44c2c1bb1c5f3be50c8de1ca5" + self.memo = "数据抓取" + self.contract_symbol = "ETHUSDT" + self.contractAPI = APIContract(self.api_key, self.secret_key, self.memo, timeout=(5, 15)) + + def get_klines(self, start_time=None, end_time=None, limit=200): + """ + 获取K线数据 + :param start_time: 开始时间戳(秒级) + :param end_time: 结束时间戳(秒级) + :param limit: 获取数量限制 + :return: K线数据列表 + """ + try: + if not end_time: + end_time = int(time.time()) + if not start_time: + start_time = end_time - 3600 * 24 * 7 # 默认获取最近7天 + + response = self.contractAPI.get_kline( + contract_symbol=self.contract_symbol, + step=30, # 30分钟 + start_time=start_time, + end_time=end_time + )[0] + + if response['code'] != 1000: + logger.error(f"获取K线失败: {response}") + return [] + + klines = response.get('data', []) + formatted = [] + for k in klines: + # BitMart API 返回的时间戳是秒级,需要转换为毫秒级 + # 根据 bitmart/框架.py 中的使用方式,API返回的是秒级时间戳 + timestamp_ms = int(k["timestamp"]) * 1000 + + formatted.append({ + 'id': timestamp_ms, + 'open': float(k["open_price"]), + 'high': float(k["high_price"]), + 'low': float(k["low_price"]), + 'close': float(k["close_price"]) + }) + + # 按时间戳排序 + formatted.sort(key=lambda x: x['id']) + return formatted + except Exception as e: + logger.error(f"获取K线异常: {e}") + return [] + + def save_klines(self, klines): + """ + 保存K线数据到数据库 + :param klines: K线数据列表 + :return: 保存的数量 + """ + saved_count = 0 + for kline in klines: + try: + BitMart30.get_or_create( + id=kline['id'], + defaults={ + 'open': kline['open'], + 'high': kline['high'], + 'low': kline['low'], + 'close': kline['close'], + } + ) + saved_count += 1 + except Exception as e: + logger.error(f"保存K线数据失败 {kline['id']}: {e}") + + return saved_count + + def collect_historical_data(self, days=30): + """ + 抓取历史数据 + :param days: 抓取最近多少天的数据 + """ + logger.info(f"开始抓取 BitMart {self.contract_symbol} 最近 {days} 天的30分钟K线数据") + + end_time = int(time.time()) + start_time = end_time - 3600 * 24 * days + + # 分批获取,每次获取7天的数据 + batch_days = 7 + total_saved = 0 + + current_start = start_time + while current_start < end_time: + current_end = min(current_start + 3600 * 24 * batch_days, end_time) + + logger.info(f"抓取时间段: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(current_start))} " + f"到 {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(current_end))}") + + klines = self.get_klines(start_time=current_start, end_time=current_end) + if klines: + saved = self.save_klines(klines) + total_saved += saved + logger.info(f"本批次保存 {saved} 条数据,累计 {total_saved} 条") + else: + logger.warning("本批次未获取到数据") + + current_start = current_end + time.sleep(1) # 避免请求过快 + + logger.success(f"数据抓取完成,共保存 {total_saved} 条K线数据") + + def collect_realtime_data(self): + """ + 实时抓取最新数据(用于定时任务) + """ + logger.info("开始抓取 BitMart 最新30分钟K线数据") + + # 获取最近1小时的数据(确保能获取到最新的K线) + end_time = int(time.time()) + start_time = end_time - 3600 * 2 # 最近2小时 + + klines = self.get_klines(start_time=start_time, end_time=end_time) + if klines: + saved = self.save_klines(klines) + logger.success(f"保存 {saved} 条最新K线数据") + else: + logger.warning("未获取到最新数据") + + +if __name__ == '__main__': + collector = BitMartDataCollector() + + # 抓取最近30天的历史数据 + collector.collect_historical_data(days=30) + + # 如果需要实时抓取,可以取消下面的注释 + # collector.collect_realtime_data() diff --git a/models/bitmart.py b/models/bitmart.py new file mode 100644 index 0000000..106fb7a --- /dev/null +++ b/models/bitmart.py @@ -0,0 +1,21 @@ +from peewee import * + +from models import db + + +class BitMart30(Model): + id = IntegerField(primary_key=True) # 时间戳(毫秒级) + open = FloatField(null=True) + high = FloatField(null=True) + low = FloatField(null=True) + close = FloatField(null=True) + + class Meta: + database = db + table_name = 'bitmart_30' + + +# 连接到数据库 +db.connect() +# 创建表(如果表不存在) +db.create_tables([BitMart30]) diff --git a/models/database.db b/models/database.db index e28aa4b42cefdae56a912f0d5883fe727e8a7249..787d2675e31ca0537c85401d63932660d3d7236f 100644 GIT binary patch literal 2437120 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