myTestFreqAI/test_future_data_protection.py
zhangkun9038@dingtalk.com 9b5f279603 prevent_future_data_leak
2025-08-19 01:14:17 +08:00

123 lines
4.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
验证防未来数据泄露策略的测试脚本
"""
import pandas as pd
import numpy as np
import logging
from datetime import datetime, timedelta
# 设置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def create_test_dataframe():
"""创建测试数据"""
dates = pd.date_range(start='2024-01-01', periods=100, freq='3min')
np.random.seed(42)
close = 100 + np.cumsum(np.random.randn(100) * 0.5)
high = close + np.abs(np.random.randn(100) * 0.2)
low = close - np.abs(np.random.randn(100) * 0.2)
open_price = close + np.random.randn(100) * 0.1
volume = np.abs(np.random.randn(100) * 1000) + 1000
return pd.DataFrame({
'date': dates,
'open': open_price,
'high': high,
'low': low,
'close': close,
'volume': volume
})
def test_vectorized_operations():
"""测试向量化操作是否避免未来数据泄露"""
df = create_test_dataframe()
original_len = len(df)
logger.info("=== 测试向量化操作 ===")
# 测试1: 使用TA-Lib计算指标安全
import talib.abstract as ta
df['rsi'] = ta.RSI(df, timeperiod=14)
df['ema200'] = ta.EMA(df, timeperiod=200)
# 验证长度一致性
assert len(df) == original_len, f"长度不匹配: {len(df)} vs {original_len}"
logger.info("✅ TA-Lib指标计算安全")
# 测试2: 使用rolling窗口安全
df['volume_ma'] = df['volume'].rolling(20).mean()
assert len(df) == original_len, f"长度不匹配: {len(df)} vs {original_len}"
logger.info("✅ Rolling窗口计算安全")
# 测试3: 使用shift获取历史数据安全
df['price_change'] = df['close'] - df['close'].shift(1)
assert len(df) == original_len, f"长度不匹配: {len(df)} vs {original_len}"
logger.info("✅ Shift操作安全")
# 测试4: 检查是否避免了iloc[-1]在业务逻辑中的使用
conditions = [
(df['rsi'] < 30),
(df['close'] < df['ema200'] * 0.95)
]
# 向量化条件计算
buy_signal = conditions[0] & conditions[1]
df['buy_signal'] = buy_signal.astype(int)
# 验证没有使用iloc[-1]做决策
assert not df['buy_signal'].isna().any(), "存在NaN值可能使用了未来数据"
logger.info("✅ 向量化条件计算安全")
return True
def test_dangerous_patterns():
"""测试危险模式(用于对比)"""
df = create_test_dataframe()
logger.info("=== 测试危险模式(对比)===")
# 危险模式1: 使用全量数据计算均值
try:
mean_price = df['close'].mean() # 这会使用未来数据
logger.warning("⚠️ 使用了全量数据均值 - 可能导致未来数据泄露")
except Exception as e:
logger.error(f"错误: {e}")
# 危险模式2: 使用iloc[-1]在业务逻辑中
try:
if len(df) > 0:
last_price = df['close'].iloc[-1] # 这在日志中可用,但不应影响决策
logger.info(f"最后价格: {last_price} - 仅用于日志记录")
except Exception as e:
logger.error(f"错误: {e}")
return True
def main():
"""主测试函数"""
logger.info("开始测试防未来数据泄露策略...")
# 测试向量化操作
test_vectorized_operations()
# 测试危险模式(对比)
test_dangerous_patterns()
logger.info("=== 测试总结 ===")
logger.info("✅ 所有向量化操作都避免了未来数据泄露")
logger.info("✅ 使用TA-Lib、rolling、shift等操作都是安全的")
logger.info("✅ 业务逻辑中避免了iloc[-1]的使用")
# 安全使用建议
logger.info("\n=== 安全使用建议 ===")
logger.info("1. 使用TA-Lib计算技术指标")
logger.info("2. 使用rolling窗口计算移动平均")
logger.info("3. 使用shift(1)获取历史数据")
logger.info("4. 避免在业务逻辑中使用全量数据计算")
logger.info("5. iloc[-1]仅用于日志记录,不影响交易决策")
if __name__ == "__main__":
main()