support get market data

This commit is contained in:
blade 2025-07-24 18:23:00 +08:00
parent ebf90534ae
commit c670be6f7d
9 changed files with 238 additions and 17 deletions

View File

@ -4,16 +4,24 @@
# API_KEY = "7286d434-225b-401f-b3af-fd595e15d23f"
# SECRET_KEY = "80B95C5757F9208F70282A85C9DDBC86"
# PASSPHRASE = "Bengbu_2001"
# SANDBOX = False
# 实盘读取API密钥配置
API_KEY = "a73f9096-8e76-49ff-947c-a4f4edf657ec"
SECRET_KEY = "F7AD69272FBF7C44E69CC110D2EDDB7A"
PASSPHRASE = "Bengbu!2001"
SANDBOX = False
# 模拟盘API密钥配置
API_KEY = "f309e789-3497-4ed3-896f-d18bdc4d9817"
SECRET_KEY = "9152809391B110E2E647FDE12A37E96D"
PASSPHRASE = "Bengbu@2001"
# API_KEY = "f309e789-3497-4ed3-896f-d18bdc4d9817"
# SECRET_KEY = "9152809391B110E2E647FDE12A37E96D"
# PASSPHRASE = "Bengbu@2001"
# SANDBOX = True
# 交易配置
TRADING_CONFIG = {
"symbol": "BTC-USDT", # 交易对
"position_size": 0.001, # 每次交易数量BTC
"sandbox": True, # 是否使用沙盒环境(建议先用沙盒测试)
# 策略参数
"sma_short_period": 5, # 短期移动平均线周期
@ -39,3 +47,19 @@ TIME_CONFIG = {
"kline_interval": "5m", # K线数据间隔
"kline_limit": 100, # K线数据条数
}
MONITOR_CONFIG = {
"volume_monitor":{
"symbols": ["XCH-USDT"],
"intervals": ["5m", "15m", "1H", "4H", "1D"],
"initial_date": "2025-07-01 00:00:00"
},
"price_monitor":{
"symbols": ["XCH-USDT"],
"intervals": [
{"interval": "5m", "threshold": 0.025},
{"interval": "15m", "threshold": 0.5},
{"interval": "1H", "threshold": 0.1}
]
}
}

View File

@ -101,14 +101,31 @@ class QuantTrader:
logging.error(f"获取价格异常: {e}")
return None
def get_kline_data(self, bar: str = '1m', limit: int = 100) -> Optional[pd.DataFrame]:
def get_kline_data(self, symbol: str = None, after: str = None, before: str = None, bar: str = '1m', limit: int = 100) -> Optional[pd.DataFrame]:
"""获取K线数据"""
if symbol is None:
symbol = self.symbol
try:
result = self.market_api.get_candlesticks(
instId=self.symbol,
bar=bar,
limit=str(limit)
)
if after is None and before is None:
result = self.market_api.get_candlesticks(
instId=symbol,
bar=bar,
limit=str(limit)
)
else:
if after is None:
after = ''
if before is None:
before = ''
if limit == 0:
limit = ''
result = self.market_api.get_candlesticks(
instId=symbol,
after=after,
before=before,
bar=bar,
limit=str(limit),
)
if result.get('code') == '0':
data = result.get('data', [])
if not data:

91
core/data_monitor.py Normal file
View File

@ -0,0 +1,91 @@
import time
from datetime import datetime, timedelta
import logging
from typing import Optional
import pandas as pd
import okx.MarketData as Market
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s: %(message)s')
class DataMonitor:
def __init__(self,
api_key: str,
secret_key: str,
passphrase: str,
sandbox: bool = True):
flag = "1" if sandbox else "0" # 0:实盘环境 1:沙盒环境
self.market_api = Market.MarketAPI(
api_key=api_key, api_secret_key=secret_key, passphrase=passphrase,
flag=flag
)
def get_historical_kline_data(self, symbol: str = None, start: str = None, bar: str = '1m', limit: int = 100, end_time: int = None) -> Optional[pd.DataFrame]:
"""
获取历史K线数据支持start为北京时间字符串%Y-%m-%d %H:%M:%S或UTC毫秒级时间戳
:param symbol: 交易对
:param start: 起始时间北京时间字符串或UTC毫秒级时间戳
:param bar: K线周期
:param limit: 每次请求数量
:param end_time: 结束时间毫秒级timestamp默认当前时间
:return: pd.DataFrame
"""
from core.utils import datetime_to_timestamp
if symbol is None:
symbol = "XCH-USDT"
if end_time is None:
end_time = int(time.time() * 1000) # 当前时间(毫秒)
# 处理start参数
if start is None:
# 默认两个月前
two_months_ago = datetime.now() - timedelta(days=60)
start_time = int(two_months_ago.timestamp() * 1000)
else:
try:
# 判断是否为纯数字UTC毫秒级timestamp
if start.isdigit():
start_time = int(start)
else:
# 按北京时间字符串处理转换为毫秒级timestamp
start_time = datetime_to_timestamp(start)
except Exception as e:
logging.error(f"start参数解析失败: {e}")
return None
columns = ["timestamp", "open", "high", "low", "close", "volume", "volCcy", "volCCyQuote", "confirm"]
all_data = []
while start_time < end_time:
try:
# after真实逻辑是获得指定时间之前的数据
response = self.market_api.get_history_candlesticks(
instId=symbol,
after=end_time, # 获取指定时间之前的数据,
bar=bar,
limit=str(limit)
)
if response["code"] != "0" or not response["data"]:
logging.warning(f"请求失败或无数据: {response.get('msg', 'No message')}")
break
candles = response["data"]
all_data.extend(candles)
# 更新 end_time 为本次请求中最早的时间戳
end_time = int(candles[-1][0])
logging.info(f"已获取 {len(candles)} 条数据,最早时间: {pd.to_datetime(end_time, unit='ms', utc=True).tz_convert('Asia/Shanghai')}")
end_time -= 1 # 减 1 毫秒以避免重复
time.sleep(0.2)
except Exception as e:
logging.error(f"请求出错: {e}")
break
if all_data:
df = pd.DataFrame(all_data, columns=columns)
df = df[df['confirm'] == '1']
for col in ['open', 'high', 'low', 'close', 'volume']:
df[col] = pd.to_numeric(df[col], errors='coerce')
dt_series = pd.to_datetime(df['timestamp'].astype(int), unit='ms', utc=True, errors='coerce').dt.tz_convert('Asia/Shanghai')
df['date_time'] = dt_series.dt.strftime('%Y-%m-%d %H:%M:%S')
df = df[['timestamp', 'date_time', 'open', 'high', 'low', 'close', 'volume']]
df.sort_values('timestamp', inplace=True)
df.reset_index(drop=True, inplace=True)
logging.info(f"总计获取 {len(df)} 条 K 线数据仅confirm=1")
return df
else:
logging.warning("未获取到数据")
return None

20
core/utils.py Normal file
View File

@ -0,0 +1,20 @@
from datetime import datetime, timezone, timedelta
def datetime_to_timestamp(date_str: str) -> int:
"""
将日期字符串 '2023-01-01 12:00:00'直接转换为毫秒级时间戳
:param date_str: 形如 '2023-01-01 12:00:00' 的日期时间字符串
:return: 毫秒级时间戳
"""
dt = datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')
return int(dt.timestamp() * 1000)
def timestamp_to_datetime(timestamp: int) -> str:
"""
将时间戳转换为日期字符串
请考虑日期字符串位于北京时区
:param timestamp: 以毫秒为单位的时间戳
:return: 形如 '2023-01-01 12:00:00' 的日期时间字符串
"""
dt = datetime.fromtimestamp(timestamp / 1000, timezone(timedelta(hours=8)))
return dt.strftime('%Y-%m-%d %H:%M:%S')

33
monitor_main.py Normal file
View File

@ -0,0 +1,33 @@
import logging
from time import sleep
from core.data_monitor import DataMonitor
from config import API_KEY, SECRET_KEY, PASSPHRASE, SANDBOX, MONITOR_CONFIG
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s: %(message)s')
class MonitorMain:
def __init__(self):
self.data_monitor = DataMonitor(
api_key=API_KEY,
secret_key=SECRET_KEY,
passphrase=PASSPHRASE,
sandbox=SANDBOX,
)
self.symbols = MONITOR_CONFIG.get("volume_monitor", {}).get("symbols", ["XCH-USDT"])
self.intervals = MONITOR_CONFIG.get("volume_monitor", {}).get("intervals", ["5m", "15m", "1H", "4H", "1D"])
self.initial_date = MONITOR_CONFIG.get("volume_monitor", {}).get("initial_date", "2025-07-01 00:00:00")
def initial_data(self):
for symbol in self.symbols:
for interval in self.intervals:
data = self.data_monitor.get_historical_kline_data(symbol=symbol,
start=self.initial_date,
bar=interval)
if __name__ == "__main__":
monitor_main = MonitorMain()
monitor_main.initial_data()

29
plan.md Normal file
View File

@ -0,0 +1,29 @@
# 量化工作计划
## 准备阶段
### API熟悉过程
1. 掌握API具体细节
- 虚拟货币价格查询
- 账户余额查询
- 现货交易买卖
- 永续合约买卖
- 设置杠杆
- 获得交易数据
### 实验阶段
1. 基于模拟盘实验
2. 设置支持永续合约权限
3. 完成现货买卖测试
4. 完成永续合约买平测试
5. 设置业务流程
- 开空单
- 卖现货
- 平空单
- 统计收益率
6. 进阶实验
- 获取对应货币技术指标
- 获取1分钟线KDJ, RSI均线等技术形态
- 如果处于超买状态,以超买形态高点为参照物
- 之后连续三个周期,价格低于形态高点价格
- 此时方便做空,利于进行业务流程操作
6. 反复验证策略安全与完整性
### 实战阶段

View File

@ -9,7 +9,7 @@ def main() -> None:
logging.info("=== 比特币量化交易系统 ===")
# 导入配置
try:
from config import API_KEY, SECRET_KEY, PASSPHRASE, TRADING_CONFIG, TIME_CONFIG
from config import API_KEY, SECRET_KEY, PASSPHRASE, SANDBOX, TRADING_CONFIG, TIME_CONFIG
except ImportError:
logging.error("找不到config.py文件请确保配置文件存在")
return
@ -18,18 +18,18 @@ def main() -> None:
logging.error("请先在config.py中配置你的OKX API密钥\n1. 登录OKX官网\n2. 进入API管理页面\n3. 创建API Key、Secret Key和Passphrase\n4. 将密钥填入config.py文件中的相应位置")
return
# 创建交易器实例
sandbox = TRADING_CONFIG.get("sandbox", True)
# sandbox = TRADING_CONFIG.get("sandbox", True)
symbol = TRADING_CONFIG.get("symbol", "BTC-USDT")
position_size = TRADING_CONFIG.get("position_size", 0.001)
trader = QuantTrader(
API_KEY, SECRET_KEY, PASSPHRASE,
sandbox=sandbox,
sandbox=SANDBOX,
symbol=symbol,
position_size=position_size
)
strategy = QuantStrategy(
API_KEY, SECRET_KEY, PASSPHRASE,
sandbox=sandbox,
sandbox=SANDBOX,
symbol=symbol,
position_size=position_size
)

View File

@ -2,7 +2,7 @@ import logging
from time import sleep
from core.base import QuantTrader
from core.strategy import QuantStrategy
from config import API_KEY, SECRET_KEY, PASSPHRASE, TRADING_CONFIG, TIME_CONFIG
from config import API_KEY, SECRET_KEY, PASSPHRASE, SANDBOX, TRADING_CONFIG, TIME_CONFIG
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s: %(message)s')
@ -12,7 +12,8 @@ class BizMain:
api_key = API_KEY
secret_key = SECRET_KEY
passphrase = PASSPHRASE
sandbox = TRADING_CONFIG.get("sandbox", True)
# sandbox = TRADING_CONFIG.get("sandbox", True)
sandbox = SANDBOX
symbol = TRADING_CONFIG.get("symbol", "BTC-USDT")
position_size = TRADING_CONFIG.get("position_size", 0.001)
self.trader = QuantTrader(api_key, secret_key, passphrase, sandbox, symbol, position_size)

6
wechat.py Normal file
View File

@ -0,0 +1,6 @@
"""
微信群发功能
建议使用企业微信
但需要管理员提供企业id以及secret信息
通过wechatpy库实现
"""