量化交易

量化交易(Quantitative Trading)也可以理解为高频交易,是利用数学模型、统计学方法和计算机编程来进行金融交易的一种策略。

移动平均交叉策略

import requests
import pandas as pd
import matplotlib.pyplot as plt
import ssl

def get_stock_data_eastmoney(stock_code, start_date, end_date):
    """
    Fetch historical stock data from Eastmoney.com
    
    Parameters:
    stock_code (str): Stock code, e.g. '002475'
    start_date (str): Start date in format 'YYYY-MM-DD'
    end_date (str): End date in format 'YYYY-MM-DD'
    
    Returns:
    DataFrame: DataFrame containing historical stock data
    """
    # Eastmoney API
    url = f"http://push2his.eastmoney.com/api/qt/stock/kline/get"
    
    # Handle stock code prefix
    if stock_code.startswith(('6', '5')):
        market_prefix = '1.'  # Shanghai market
    else:
        market_prefix = '0.'  # Shenzhen market
    secid = f"{market_prefix}{stock_code}"
    
    # Request parameters
    params = {
        "secid": secid,
        "ut": "fa5fd1943c7b386f1734de82369f10d",
        "fields1": "f1,f2,f3,f4,f5,f6",
        "fields2": "f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61",
        "klt": "101",  # Daily K-line
        "fqt": "0",  # No adjustment
        "beg": start_date.replace('-', ''),
        "end": end_date.replace('-', '')
    }
    
    # Set request headers
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
    }
    
    try:
        # Bypass SSL verification (handle corporate network issues)
        ssl._create_default_https_context = ssl._create_unverified_context
        
        # Send request
        response = requests.get(url, params=params, headers=headers)
        response.raise_for_status()
        data = response.json()
        
        if data.get('data') and 'klines' in data['data']:
            # Parse K-line data
            klines = data['data']['klines']
            if not klines:
                print(f"Retrieved K-line data is empty")
                return None
            
            # Create DataFrame
            df = pd.DataFrame([kline.split(',')[:7] for kline in klines],
                             columns=['Date', 'Open', 'Close', 'High', 'Low', 'Volume', 'Turnover'])
            
            # Convert data types
            numeric_columns = ['Open', 'Close', 'High', 'Low', 'Volume', 'Turnover']
            df[numeric_columns] = df[numeric_columns].apply(pd.to_numeric)
            
            # Convert date column to datetime type
            df['Date'] = pd.to_datetime(df['Date'])
            
            # Set date as index
            df.set_index('Date', inplace=True)
            
            return df
        else:
            print(f"Failed to retrieve data for stock {stock_code}: {data.get('msg', 'Unknown error')}")
            return None
            
    except requests.exceptions.RequestException as e:
        print(f"Request exception for stock {stock_code}: {e}")
        return None
    except Exception as e:
        print(f"Error processing stock {stock_code}: {e}")
        return None

# Get Luxshare stock data
symbol = "002475"
start_date = "2020-01-01"
end_date = "2025-08-18"

print(f"Fetching stock {symbol} data from {start_date} to {end_date}...")
data = get_stock_data_eastmoney(symbol, start_date, end_date)

if data is not None and not data.empty:
    print("Data retrieved successfully!")
    
    # Use 'Close' column for calculations
    close_column = 'Close'
    
    # Calculate short-term (50-day) and long-term (200-day) moving averages
    data['MA_50'] = data[close_column].rolling(window=50).mean()
    data['MA_200'] = data[close_column].rolling(window=200).mean()

    # Generate buy/sell signals
    data['Signal'] = 0
    data['Signal'][data['MA_50'] > data['MA_200']] = 1   # Short-term MA crosses above long-term MA, generate buy signal
    data['Signal'][data['MA_50'] < data['MA_200']] = -1  # Short-term MA crosses below long-term MA, generate sell signal

    # To better display buy/sell signals, find signal change points
    data['Position'] = data['Signal'].diff()
    
    # Plot stock price and moving averages
    plt.figure(figsize=(14, 8))
    plt.plot(data[close_column], label='Close Price')
    plt.plot(data['MA_50'], label='50-day Moving Average')
    plt.plot(data['MA_200'], label='200-day Moving Average')

    # Mark buy/sell signals
    buy_signals = data[data['Position'] == 1]
    sell_signals = data[data['Position'] == -1]
    
    plt.scatter(buy_signals.index, buy_signals['MA_50'], marker='^', color='g', s=100, label='Buy Signal', zorder=5)
    plt.scatter(sell_signals.index, sell_signals['MA_50'], marker='v', color='r', s=100, label='Sell Signal', zorder=5)

    plt.title(f"Luxshare ({symbol}) Stock Price with Moving Average Strategy")
    plt.xlabel("Date")
    plt.ylabel("Price (CNY)")
    plt.legend()
    plt.grid(True, alpha=0.3)
    plt.tight_layout()
    plt.show()
    
    # Display basic data statistics
    print("\nBasic Data Statistics:")
    print(data[[close_column, 'MA_50', 'MA_200', 'Signal']].describe())
    
    # Display recent buy/sell signals
    print("\nRecent Buy/Sell Signals:")
    recent_signals = data[data['Position'] != 0].tail(10)
    for date, row in recent_signals.iterrows():
        signal_type = "Buy" if row['Position'] == 1 else "Sell"
        print(f"{date.date()}: {signal_type} Signal - Price: {row[close_column]:.2f}")
        
    # Display current status
    if not data.empty:
        latest = data.iloc[-1]
        print(f"\nCurrent Status:")
        print(f"Current Price: {latest[close_column]:.2f}")
        print(f"50-day MA: {latest['MA_50']:.2f}")
        print(f"200-day MA: {latest['MA_200']:.2f}")
        print(f"Current Signal: {'Hold' if latest['Signal'] == 1 else 'No Position'}")
        
else:
    print("Failed to retrieve valid data")

image

 这里计算出40是买点,感觉也不大准啊

量化交易基本策略

量化交易基于数学模型、统计学和计算机算法,通过系统性的方法识别和执行交易机会。

以下是一些常见的量化交易基本策略:

量化交易基于数学模型、统计学和计算机算法,通过系统性的方法识别和执行交易机会。

以下是一些常见的量化交易基本策略:

1. 移动平均策略

  • 策略思想: 基于股价的历史平均值,通过计算短期和长期移动平均线之间的差异来产生买卖信号。

  • 实现方式: 计算短期和长期移动平均,当短期均线上穿长期均线时产生买入信号,反之产生卖出信号。

2. 均值回归策略

  • 策略思想: 基于价格的历史波动,认为价格在波动后会回归到其平均水平。

  • 实现方式: 通过计算价格与均值之间的差异,当价格偏离均值过多时产生买入或卖出信号。

3. 动量策略

  • 策略思想: 基于价格的趋势,认为价格趋势会延续一段时间。

  • 实现方式: 通过计算价格的变化率或其他趋势指标,产生买入或卖出信号。

4. 市场中性策略

  • 策略思想: 通过同时进行买入和卖出,以利用市场的相对强弱。

  • 实现方式: 基于两个或多个相关资产之间的价差或相关性,产生交易信号。

5. 统计套利策略

  • 策略思想: 基于统计学原理,寻找价格之间的临时不平衡,以实现套利。

  • 实现方式: 通过寻找价格、波动性或其他统计指标的异常值,产生交易信号。

6. 事件驱动策略

  • 策略思想: 基于特定事件或信息的发生,产生交易信号。

  • 实现方式: 监控新闻、财报、经济指标等,当发生特定事件时执行交易。

7. 机器学习策略

  • 策略思想: 利用机器学习算法从大量数据中学习模式,预测未来价格走势。

  • 实现方式: 使用回归、分类或深度学习模型,训练模型预测市场走势。

8. 高频交易策略

  • 策略思想: 通过快速执行大量交易来利用极短时间内的小价差。

  • 实现方式: 使用高性能算法和快速执行系统,通常涉及大量交易和低持仓时间。

中国 A 股的股票代码需要加上交易所的后缀,上海证券交易所(SSE)的后缀是 .SS,深圳证券交易所(SZSE)的后缀是 .SZ。

量化回测

通过回测,交易者可以了解其策略在不同市场条件下的表现,并进行优化和改进。

import requests
import pandas as pd
import matplotlib.pyplot as plt
import ssl

def get_stock_data_eastmoney(stock_code, start_date, end_date):
    """
    Fetch historical stock data from Eastmoney.com
    
    Parameters:
    stock_code (str): Stock code, e.g. '002475'
    start_date (str): Start date in format 'YYYY-MM-DD'
    end_date (str): End date in format 'YYYY-MM-DD'
    
    Returns:
    DataFrame: DataFrame containing historical stock data
    """
    # Eastmoney API
    url = f"http://push2his.eastmoney.com/api/qt/stock/kline/get"
    
    # Handle stock code prefix
    if stock_code.startswith(('6', '5')):
        market_prefix = '1.'  # Shanghai market
    else:
        market_prefix = '0.'  # Shenzhen market
    secid = f"{market_prefix}{stock_code}"
    
    # Request parameters
    params = {
        "secid": secid,
        "ut": "fa5fd1943c7b386f1734de82369f10d",
        "fields1": "f1,f2,f3,f4,f5,f6",
        "fields2": "f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61",
        "klt": "101",  # Daily K-line
        "fqt": "0",  # No adjustment
        "beg": start_date.replace('-', ''),
        "end": end_date.replace('-', '')
    }
    
    # Set request headers
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
    }
    
    try:
        # Bypass SSL verification (handle corporate network issues)
        ssl._create_default_https_context = ssl._create_unverified_context
        
        # Send request
        response = requests.get(url, params=params, headers=headers)
        response.raise_for_status()
        data = response.json()
        
        if data.get('data') and 'klines' in data['data']:
            # Parse K-line data
            klines = data['data']['klines']
            if not klines:
                print(f"Retrieved K-line data is empty")
                return None
            
            # Create DataFrame
            df = pd.DataFrame([kline.split(',')[:7] for kline in klines],
                             columns=['Date', 'Open', 'Close', 'High', 'Low', 'Volume', 'Turnover'])
            
            # Convert data types
            numeric_columns = ['Open', 'Close', 'High', 'Low', 'Volume', 'Turnover']
            df[numeric_columns] = df[numeric_columns].apply(pd.to_numeric)
            
            # Convert date column to datetime type
            df['Date'] = pd.to_datetime(df['Date'])
            
            # Set date as index
            df.set_index('Date', inplace=True)
            
            return df
        else:
            print(f"Failed to retrieve data for stock {stock_code}: {data.get('msg', 'Unknown error')}")
            return None
            
    except requests.exceptions.RequestException as e:
        print(f"Request exception for stock {stock_code}: {e}")
        return None
    except Exception as e:
        print(f"Error processing stock {stock_code}: {e}")
        return None

# Get Luxshare stock data for detailed analysis
symbol = "002475"
start_date = "2022-01-01"
end_date = "2025-08-18"

print(f"Fetching stock {symbol} data from {start_date} to {end_date} for detailed analysis...")
data = get_stock_data_eastmoney(symbol, start_date, end_date)

if data is not None and not data.empty:
    print("Data retrieved successfully! Performing detailed analysis...")
    
    # Use 'Close' column for calculations
    close_column = 'Close'
    
    # Calculate moving averages
    data['SMA_50'] = data[close_column].rolling(window=50).mean()
    data['SMA_200'] = data[close_column].rolling(window=200).mean()

    # Initialize signal column
    data['Signal'] = 0

    # Calculate crossover signals
    data.loc[data['SMA_50'] > data['SMA_200'], 'Signal'] = 1
    data.loc[data['SMA_50'] < data['SMA_200'], 'Signal'] = -1

    # Calculate daily returns
    data['Daily_Return'] = data[close_column].pct_change()

    # Calculate strategy returns (shift(1) to avoid look-ahead bias)
    data['Strategy_Return'] = data['Signal'].shift(1) * data['Daily_Return']

    # Calculate cumulative returns
    data['Cumulative_Return'] = (1 + data['Strategy_Return']).cumprod()
    
    # Calculate buy and hold cumulative returns for comparison
    data['Buy_Hold_Return'] = (1 + data['Daily_Return']).cumprod()

    # Find trade signals
    data['Position'] = data['Signal'].diff()
    
    # Detailed analysis
    print("=== Detailed Strategy Analysis ===")
    
    # Price change analysis
    initial_price = data[close_column].iloc[0]
    final_price = data[close_column].iloc[-1]
    price_change = (final_price / initial_price) - 1
    
    print(f"Initial Price: {initial_price:.2f}")
    print(f"Final Price: {final_price:.2f}")
    print(f"Price Change: {price_change:.2%}")
    
    # Strategy performance
    strategy_return = data['Cumulative_Return'].iloc[-1] - 1
    buy_hold_return = data['Buy_Hold_Return'].iloc[-1] - 1
    
    print(f"\nStrategy Return: {strategy_return:.2%}")
    print(f"Buy & Hold Return: {buy_hold_return:.2%}")
    
    # Signal timing analysis
    print(f"\n=== Signal Timing Analysis ===")
    signals = data[data['Position'] != 0].copy()
    if len(signals) > 0:
        print("Recent Trade Signals:")
        for date, row in signals.tail(10).iterrows():
            signal_type = "BUY" if row['Position'] == 1 else "SELL"
            print(f"{date.date()}: {signal_type} at price {row[close_column]:.2f}")
    
    # Check if we're currently holding
    current_signal = data['Signal'].iloc[-1]
    print(f"\nCurrent Position: {'HOLDING' if current_signal == 1 else 'NOT HOLDING'}")
    
    # Period by period analysis
    print(f"\n=== Key Period Analysis ===")
    
    # Find when strategy was holding vs not holding
    holding_periods = data[data['Signal'] == 1]
    not_holding_periods = data[data['Signal'] == -1]
    
    if len(holding_periods) > 0:
        holding_return = (holding_periods['Daily_Return'] + 1).prod() - 1
        print(f"Return during holding periods: {holding_return:.2%}")
        print(f"Total holding days: {len(holding_periods)}")
    
    if len(not_holding_periods) > 0:
        not_holding_return = (not_holding_periods['Daily_Return'] + 1).prod() - 1
        print(f"Return during non-holding periods: {not_holding_return:.2%}")
        print(f"Total non-holding days: {len(not_holding_periods)}")
    
    # Drawdown analysis
    data['Strategy_Drawdown'] = (data['Cumulative_Return'] / data['Cumulative_Return'].cummax()) - 1
    data['Buy_Hold_Drawdown'] = (data['Buy_Hold_Return'] / data['Buy_Hold_Return'].cummax()) - 1
    
    max_strategy_drawdown = data['Strategy_Drawdown'].min()
    max_buy_hold_drawdown = data['Buy_Hold_Drawdown'].min()
    
    print(f"\n=== Drawdown Analysis ===")
    print(f"Maximum Strategy Drawdown: {max_strategy_drawdown:.2%}")
    print(f"Maximum Buy & Hold Drawdown: {max_buy_hold_drawdown:.2%}")
    
    # Plot detailed chart
    fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(14, 10))
    
    # Price and signals plot
    ax1.plot(data.index, data[close_column], label='Close Price', linewidth=1)
    ax1.plot(data.index, data['SMA_50'], label='50-day MA', alpha=0.7)
    ax1.plot(data.index, data['SMA_200'], label='200-day MA', alpha=0.7)
    
    # Mark buy/sell signals
    buy_signals = data[data['Position'] == 1]
    sell_signals = data[data['Position'] == -1]
    
    ax1.scatter(buy_signals.index, buy_signals[close_column], 
               marker='^', color='green', s=100, label='Buy Signal', zorder=5)
    ax1.scatter(sell_signals.index, sell_signals[close_column], 
               marker='v', color='red', s=100, label='Sell Signal', zorder=5)
    
    ax1.set_title(f'{symbol} Price and Trading Signals')
    ax1.set_ylabel('Price')
    ax1.legend()
    ax1.grid(True, alpha=0.3)
    
    # Returns comparison plot
    ax2.plot(data.index, data['Cumulative_Return'], label='Strategy Return', color='blue')
    ax2.plot(data.index, data['Buy_Hold_Return'], label='Buy & Hold Return', color='green')
    
    ax2.set_title('Cumulative Returns Comparison')
    ax2.set_ylabel('Cumulative Return')
    ax2.set_xlabel('Date')
    ax2.legend()
    ax2.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.show()
    
else:
    print("Failed to retrieve valid data for analysis")

image

 根据日均线策略,结果回测收益亏的一塌糊涂。

posted @ 2025-08-18 17:14  嘉禾世兴  阅读(27)  评论(0)    收藏  举报