In [1]:
# %pip install tushare pandas numpy matplotlib
In [2]:
import tushare as ts
# ts.set_token('YourTokenHere')

def get_tushare_token(file_path='tushare_token.txt'):
    """
    从文件读取 Tushare Token
    
    :param file_path: Token文件路径
    :return: Token字符串
    """
    try:
        with open(file_path, 'r') as file:
            # 读取第一行并去除可能的空白字符
            token = file.readline().strip()
            return token
    except FileNotFoundError:
        print(f"Error: Token文件 {file_path} 未找到")
        return None
    except Exception as e:
        print(f"读取Token时发生错误: {e}")
        return None

# 在代码中使用
token = get_tushare_token()
ts.set_token(token)

ver5

In [3]:
import tushare as ts
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from itertools import product

class MAStrategy:
    def __init__(self, short_window=20, long_window=50):
        self.short_window = short_window
        self.long_window = long_window
    
    def get_data(self, stock_code, start_date, end_date):
        """
        数据获取方法
        """
        pro = ts.pro_api()
        df = pro.daily(
            ts_code=stock_code, 
            start_date=start_date.replace('-', ''), 
            end_date=end_date.replace('-', '')
        )
        
        # 数据预处理
        df['date'] = pd.to_datetime(df['trade_date'], format='%Y%m%d')
        df = df.sort_values('date').set_index('date')
        
        return df

    def generate_signals(self, df, short_window, long_window):
        """
        生成交易信号
        """
        # 计算移动平均线
        df['short_ma'] = df['close'].rolling(window=short_window).mean()
        df['long_ma'] = df['close'].rolling(window=long_window).mean()
        
        # 初始化信号列
        df['signal'] = 0
        
        # 生成交易信号
        # 买入信号: 上穿判断
        df.loc[(df['short_ma'] > df['long_ma']) & 
               (df['short_ma'].shift(1) <= df['long_ma'].shift(1)), 'signal'] = 1 
        # 卖出信号: 下穿判断
        df.loc[(df['short_ma'] < df['long_ma']) & 
               (df['short_ma'].shift(1) >= df['long_ma'].shift(1)), 'signal'] = -1
        
        return df

    def backtest(self, df, initial_capital=100000, commission_rate=0.002):
        """
        回测分析
        """
        # 计算每日收益率
        df['returns'] = df['close'].pct_change()
        
        # 初始化账户
        df['position'] = df['signal'].shift(1)  # 根据前一日信号决定当日仓位
        df['portfolio_returns'] = df['returns'] * df['position']
        
        # 扣除交易成本
        df['net_returns'] = df['portfolio_returns'] - abs(df['position'].diff()) * commission_rate
        
        # 计算累计收益
        df['cumulative_returns'] = (1 + df['net_returns']).cumprod()
        
        # 生成交易列表
        trades = df.reset_index()
        trade_points = trades[trades['position'] != trades['position'].shift(1)].copy()
        trade_points['trade_type'] = np.where(trade_points['position'] == 1, 'Buy', 'Sell')
        
        # 性能指标
        performance = {
            'total_return': df['cumulative_returns'].iloc[-1] - 1,
            'annual_return': (df['cumulative_returns'].iloc[-1] ** (252/len(df)) - 1),
            'sharpe_ratio': df['net_returns'].mean() / df['net_returns'].std() * np.sqrt(252),
            'max_drawdown': (df['cumulative_returns'] / df['cumulative_returns'].cummax() - 1).min()
        }
        
        return df, trade_points, performance

    def visualize_strategy(self, df, trades, stock_code, period):
        """
        可视化策略:
        1. 均线图
        2. 策略收益率曲线
        """
        # 创建两个子图
        fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(15, 10), 
                                       gridspec_kw={'height_ratios': [2, 1]})
        
        # 第一个子图:均线图
        ax1.plot(df.index, df['close'], label='股价', color='black')
        ax1.plot(df.index, df['short_ma'], label=f'短期均线({self.short_window}日)', color='red')
        ax1.plot(df.index, df['long_ma'], label=f'长期均线({self.long_window}日)', color='blue')
        
        # 标注买卖点
        buy_points = trades[trades['trade_type'] == 'Buy']
        sell_points = trades[trades['trade_type'] == 'Sell']
        
        ax1.scatter(buy_points['date'], buy_points['close'], 
                    color='red', marker='^', label='买入点')
        ax1.scatter(sell_points['date'], sell_points['close'], 
                    color='green', marker='v', label='卖出点')
        
        ax1.set_title(f'{stock_code} 均线策略 ({period})')
        ax1.set_xlabel('日期')
        ax1.set_ylabel('股价')
        ax1.legend()
        
        # 第二个子图:策略收益率曲线
        ax2.plot(df.index, df['cumulative_returns'], label='策略累计收益', color='purple')
        ax2.set_title('策略累计收益率')
        ax2.set_xlabel('日期')
        ax2.set_ylabel('累计收益率')
        ax2.legend()
        
        plt.tight_layout()
        plt.show()

    def parameter_optimization(self, stock_code, start_date, end_date):
        """
        参数网格搜索优化
        """
        short_windows = [5, 10, 15, 20]
        long_windows = [20, 30, 40, 50, 60]
        
        optimization_results = []
        
        for short_window, long_window in product(short_windows, long_windows):
            if short_window >= long_window:
                continue
            
            df = self.get_data(stock_code, start_date, end_date)
            df = self.generate_signals(df, short_window, long_window)
            _, trades, performance = self.backtest(df)
            
            optimization_results.append({
                'short_window': short_window,
                'long_window': long_window,
                'performance': performance
            })
        
        optimization_results.sort(key=lambda x: x['performance']['total_return'], reverse=True)
        
        return optimization_results

    def performance_evaluation(self, stock_codes, periods):
        """
        多标的、多时期性能评估
        """
        comprehensive_results = {}
        
        for stock_code in stock_codes:
            stock_performance = []
            
            for start_date, end_date in periods:
                try:
                    df = self.get_data(stock_code, start_date, end_date)
                    
                    # 参数优化
                    optimization_results = self.parameter_optimization(stock_code, start_date, end_date)
                    best_params = optimization_results[0]
                    
                    # 使用最佳参数
                    df = self.generate_signals(
                        df, 
                        best_params['short_window'], 
                        best_params['long_window']
                    )
                    
                    result_df, trades, performance = self.backtest(df)
                    
                    # 可视化
                    self.visualize_strategy(result_df, trades, stock_code, f'{start_date} to {end_date}')
                    
                    stock_performance.append({
                        'period': f'{start_date} to {end_date}',
                        'best_params': best_params,
                        'performance': performance,
                        'trades': trades
                    })
                
                except Exception as e:
                    print(f"股票 {stock_code} 在 {start_date} 到 {end_date} 期间回测失败: {e}")
            
            comprehensive_results[stock_code] = stock_performance
        
        return comprehensive_results

def main():
    # 实例化策略
    strategy = MAStrategy()
    
    # 设置回测参数
    stock_codes = ['600036.SH', '000001.SZ']  # 招商银行、平安银行
    periods = [
        ('2020-01-01', '2020-12-31'),  # 牛市
        ('2021-01-01', '2021-12-31'),  # 震荡市
        ('2022-01-01', '2022-12-31')   # 熊市
    ]
    
    # 执行性能评估
    results = strategy.performance_evaluation(stock_codes, periods)
    
    # 输出结果
    for stock_code, stock_performance in results.items():
        print(f"\n股票 {stock_code} 表现:")
        
        for period_result in stock_performance:
            print(f"\n期间: {period_result['period']}")
            print("最佳参数:")
            print(f"短期均线: {period_result['best_params']['short_window']}")
            print(f"长期均线: {period_result['best_params']['long_window']}")
            
            print("\n性能指标:")
            for key, value in period_result['performance'].items():
                print(f"{key}: {value:.4f}")
            
            print("\n交易列表:")
            trades = period_result['trades']
            print(trades[['date', 'close', 'trade_type']])

if __name__ == "__main__":
    main()
Duplicate key in file WindowsPath('d:/Users/wukek/anaconda3/Lib/site-packages/matplotlib/mpl-data/matplotlibrc'), line 412 ('axes.unicode_minus: True  # use Unicode for the minus symbol rather than hyphen.  See')
股票 600036.SH 表现:

期间: 2020-01-01 to 2020-12-31
最佳参数:
短期均线: 5
长期均线: 20

性能指标:
total_return: 0.1293
annual_return: 0.1344
sharpe_ratio: 1.1791
max_drawdown: -0.0318

交易列表:
          date  close trade_type
0   2020-01-02  38.88       Sell
1   2020-01-03  39.40       Sell
62  2020-04-08  32.22        Buy
63  2020-04-09  32.30       Sell
93  2020-05-26  33.43       Sell
94  2020-05-27  33.43       Sell
99  2020-06-03  35.22        Buy
100 2020-06-04  35.15       Sell
109 2020-06-17  34.20       Sell
110 2020-06-18  33.89       Sell
120 2020-07-06  40.41        Buy
121 2020-07-07  41.06       Sell
131 2020-07-21  36.84       Sell
132 2020-07-22  36.44       Sell
144 2020-08-07  36.61        Buy
145 2020-08-10  37.00       Sell
162 2020-09-02  37.20       Sell
163 2020-09-03  36.98       Sell
172 2020-09-16  38.06        Buy
173 2020-09-17  37.87       Sell
181 2020-09-29  36.31       Sell
182 2020-09-30  36.00       Sell
188 2020-10-16  39.78        Buy
189 2020-10-19  39.99       Sell
228 2020-12-11  42.68       Sell
229 2020-12-14  44.37       Sell

期间: 2021-01-01 to 2021-12-31
最佳参数:
短期均线: 10
长期均线: 60

性能指标:
total_return: 0.0812
annual_return: 0.0843
sharpe_ratio: 1.1397
max_drawdown: -0.0310

交易列表:
          date  close trade_type
0   2021-01-04  43.17       Sell
1   2021-01-05  42.18       Sell
61  2021-04-07  50.43       Sell
62  2021-04-08  50.50       Sell
79  2021-05-06  53.67        Buy
80  2021-05-07  54.18       Sell
123 2021-07-08  50.35       Sell
124 2021-07-09  49.90       Sell
169 2021-09-10  54.12        Buy
170 2021-09-13  53.92       Sell
182 2021-10-08  50.93       Sell
183 2021-10-11  53.00       Sell
184 2021-10-12  53.09        Buy
185 2021-10-13  53.03       Sell
209 2021-11-16  52.50       Sell
210 2021-11-17  51.84       Sell
213 2021-11-22  51.69        Buy
214 2021-11-23  51.75       Sell
218 2021-11-29  49.82       Sell
219 2021-11-30  49.49       Sell
231 2021-12-16  51.20        Buy
232 2021-12-17  50.77       Sell
234 2021-12-21  50.63       Sell
235 2021-12-22  50.01       Sell

期间: 2022-01-01 to 2022-12-31
最佳参数:
短期均线: 10
长期均线: 40

性能指标:
total_return: 0.0503
annual_return: 0.0524
sharpe_ratio: 0.9230
max_drawdown: -0.0168

交易列表:
          date  close trade_type
0   2022-01-04  48.35       Sell
1   2022-01-05  49.05       Sell
106 2022-06-16  39.96        Buy
107 2022-06-17  39.85       Sell
127 2022-07-15  34.87       Sell
128 2022-07-18  35.63       Sell
170 2022-09-15  36.01        Buy
171 2022-09-16  34.95       Sell
183 2022-10-11  31.40       Sell
184 2022-10-12  30.95       Sell
212 2022-11-21  31.87        Buy
213 2022-11-22  32.45       Sell

股票 000001.SZ 表现:

期间: 2020-01-01 to 2020-12-31
最佳参数:
短期均线: 5
长期均线: 60

性能指标:
total_return: 0.1094
annual_return: 0.1137
sharpe_ratio: 1.1159
max_drawdown: -0.0054

交易列表:
          date  close trade_type
0   2020-01-02  16.87       Sell
1   2020-01-03  17.18       Sell
82  2020-05-11  14.00        Buy
83  2020-05-12  13.79       Sell
86  2020-05-15  13.23       Sell
87  2020-05-18  13.20       Sell
101 2020-06-05  13.59        Buy
102 2020-06-08  13.62       Sell
109 2020-06-17  12.85       Sell
110 2020-06-18  12.76       Sell
120 2020-07-06  15.68        Buy
121 2020-07-07  15.48       Sell
138 2020-07-30  13.37       Sell
139 2020-07-31  13.34       Sell
143 2020-08-06  13.90        Buy
144 2020-08-07  13.70       Sell

期间: 2021-01-01 to 2021-12-31
最佳参数:
短期均线: 15
长期均线: 60

性能指标:
total_return: 0.0799
annual_return: 0.0830
sharpe_ratio: 1.2971
max_drawdown: -0.0020

交易列表:
          date  close trade_type
0   2021-01-04  18.60       Sell
1   2021-01-05  18.17       Sell
80  2021-05-07  24.05        Buy
81  2021-05-10  23.86       Sell
119 2021-07-02  21.81       Sell
120 2021-07-05  22.06       Sell
193 2021-10-25  20.12        Buy
194 2021-10-26  20.05       Sell
205 2021-11-10  17.40       Sell
206 2021-11-11  18.35       Sell

期间: 2022-01-01 to 2022-12-31
最佳参数:
短期均线: 5
长期均线: 30

性能指标:
total_return: 0.1162
annual_return: 0.1213
sharpe_ratio: 1.7134
max_drawdown: -0.0164

交易列表:
          date  close trade_type
0   2022-01-04  16.66       Sell
1   2022-01-05  17.15       Sell
59  2022-04-06  16.39        Buy
60  2022-04-07  16.28       Sell
76  2022-04-29  15.32       Sell
77  2022-05-05  15.32       Sell
109 2022-06-21  14.37        Buy
110 2022-06-22  14.08       Sell
111 2022-06-23  14.20       Sell
112 2022-06-24  14.23       Sell
116 2022-06-30  14.98        Buy
117 2022-07-01  14.92       Sell
126 2022-07-14  13.37       Sell
127 2022-07-15  13.24       Sell
160 2022-08-31  12.75        Buy
161 2022-09-01  12.61       Sell
176 2022-09-23  12.29       Sell
177 2022-09-26  12.00       Sell
208 2022-11-15  12.01        Buy
209 2022-11-16  11.82       Sell
In [5]:
    # 实例化策略
    strategy = MAStrategy()
    
    # 设置回测参数
    # stock_codes = ['600036.SH', '000001.SZ']  # 招商银行、平安银行
    # periods = [
    #     ('2020-01-01', '2020-12-31'),  # 牛市
    #     ('2021-01-01', '2021-12-31'),  # 震荡市
    #     ('2022-01-01', '2022-12-31')   # 熊市
    # ]
    stock_codes = ['600036.SH']  # 招商银行、平安银行
    periods = [
        ('2020-01-01', '2020-12-31')
    ]
    
    # 执行性能评估
    results = strategy.performance_evaluation(stock_codes, periods)
    
    # 输出结果
    for stock_code, stock_performance in results.items():
        print(f"\n股票 {stock_code} 表现:")
        
        for period_result in stock_performance:
            print(f"\n期间: {period_result['period']}")
            print("最佳参数:")
            print(f"短期均线: {period_result['best_params']['short_window']}")
            print(f"长期均线: {period_result['best_params']['long_window']}")
            
            print("\n性能指标:")
            for key, value in period_result['performance'].items():
                print(f"{key}: {value:.4f}")
            
            print("\n交易列表:")
            trades = period_result['trades']
            print(trades[['date', 'close', 'trade_type']])
股票 600036.SH 表现:

期间: 2020-01-01 to 2020-12-31
最佳参数:
短期均线: 5
长期均线: 20

性能指标:
total_return: 0.1293
annual_return: 0.1344
sharpe_ratio: 1.1791
max_drawdown: -0.0318

交易列表:
          date  close trade_type
0   2020-01-02  38.88       Sell
1   2020-01-03  39.40       Sell
62  2020-04-08  32.22        Buy
63  2020-04-09  32.30       Sell
93  2020-05-26  33.43       Sell
94  2020-05-27  33.43       Sell
99  2020-06-03  35.22        Buy
100 2020-06-04  35.15       Sell
109 2020-06-17  34.20       Sell
110 2020-06-18  33.89       Sell
120 2020-07-06  40.41        Buy
121 2020-07-07  41.06       Sell
131 2020-07-21  36.84       Sell
132 2020-07-22  36.44       Sell
144 2020-08-07  36.61        Buy
145 2020-08-10  37.00       Sell
162 2020-09-02  37.20       Sell
163 2020-09-03  36.98       Sell
172 2020-09-16  38.06        Buy
173 2020-09-17  37.87       Sell
181 2020-09-29  36.31       Sell
182 2020-09-30  36.00       Sell
188 2020-10-16  39.78        Buy
189 2020-10-19  39.99       Sell
228 2020-12-11  42.68       Sell
229 2020-12-14  44.37       Sell