python 代码主要实现了从米筐数据平台(RQData)获取期货数据,将数据存储到ClickHouse数据库,并进行一些趋势计算和因子保存的功能

# 忽略某些模块的提示信息
import warnings
warnings.filterwarnings("ignore")
# 在全局配置中添加RQData账号信息
import rqdatac as rq 

from typing import List
import pandas as pd
import numpy as np
import re
from datetime import datetime, timedelta,time
from dateutil.relativedelta import relativedelta
from vnsw.alpha_research.data_center import DataCenter
from vnpy.trader.constant import Exchange, Interval
from vnpy.trader.setting import SETTINGS
rq.init(username=SETTINGS["datafeed.username"],password=SETTINGS["datafeed.password"])

def to_clickhouse(dc,table_name,df):
    SAVE_REFERENCE_QUERY = "INSERT INTO {table} VALUES"
    query = SAVE_REFERENCE_QUERY.format(table=table_name)

    # 生成更新时间列
    update = datetime.now()
    df["update"] =update
    # 生成要传参用的DataFrame
    # 写入数据库并返回条数
    try:
        dc.client.insert_dataframe(query, df)
        print('已存储',set(df['symbol']),min(df['interval']),min(df['datetime']),'至',max(df['datetime']))
    except Exception as e:
        print ("报错",e)

def load_rq_data(symbols:List[str],exchange:Exchange,start_date:datetime,end_date:datetime,frequency:str)->pd.DataFrame:#米筐的total_turnover是成交额,open_interest是持仓量
    if frequency=='1d' or frequency=='1m':
        df=rq.get_price(symbols, start_date, end_date,frequency,expect_df=True).reset_index()
    else:
        df=pd.DataFrame()
        start_date=start_date.replace(hour=0, minute=0, second=0,microsecond=0)
        while start_date<end_date:
            # print(start_date)
            df2=rq.get_price(symbols, start_date, start_date,frequency,expect_df=True) #米筐不看时分秒,会把所有涵盖日期的所有的x分钟bar返回
            if df2 is None:
                start_date+=relativedelta(days=1)
                continue
            elif len(df2):
                # print(df2)
                df=pd.concat([df,df2.reset_index()])
            start_date+=relativedelta(days=1)
        if max(df['datetime']).time()<time(15, 15):
            df.drop(df[df['datetime']==max(df['datetime'])].index,inplace=True)  
  
    df.rename(columns={'order_book_id':'symbol','date':'datetime','close':'close_price','open':'open_price','high':'high_price','low':'low_price','volume':'volume','open_interest':'open_interest','total_turnover':'turnover','settlement':'settlement_price'},inplace=True)
    df['exchange']=exchange.value
    df['interval']=frequency
    df['turnover']=np.nan
    if frequency!='1d':
        df['settlement_price']=np.nan
    else:
        df['interval']='d'
    df=df[['symbol','exchange','interval','datetime','volume','open_interest','open_price','high_price','low_price','close_price','settlement_price','turnover']]
    # print(df)
    return df

#入库国债期货全部后复权行情
def save_bond_future_889_history(dc,start_date,end_date=datetime.now(),frequency:str='1d'):
    table_name = "ficc.bar_data_new"
    exchange=Exchange.CFFEX
    symbols_head=['T','TF','TS','TL','IH','IF','IC','IM']
    symbols=[symbol+'889' for symbol in symbols_head]
    df=pd.DataFrame()
    df=load_rq_data(symbols,exchange,start_date,end_date,frequency)
    if len(df):
        to_clickhouse(dc,table_name,df)

#入库具体国债期货历史行情数据
def save_bond_future_history(dc,start_date,end_date=datetime.now(),frequency:str='1d'):
    bond_start_date={'T':datetime(2015,3,20),'TF':datetime(2013,9,6),'TS':datetime(2018,8,17),'TL':datetime(2023,4,21),
                     'IH':datetime(2015,4,16),'IF':datetime(2010,4,16),'IC':datetime(2015,4,16),'IM':datetime(2022,7,22)}
    to_year=end_date.year
    to_month=end_date.month
    table_name = "ficc.bar_data_new"
    exchange=Exchange.CFFEX
    for symbol_head in ['T','TF','TS','TL']:
        start_year=max(bond_start_date[symbol_head],start_date).year
        start_month=max(bond_start_date[symbol_head],start_date).month
        for year in range(start_year,to_year+2):
            for month in [3,6,9,12]:
                df=pd.DataFrame()
                symbol=symbol_head+str(year-2000)+str(month).zfill(2)
                load_start_date=max(datetime(year,month,1)-relativedelta(years=1),start_date)
                if load_start_date>end_date:
                    continue
                load_end_date=min(datetime(year,month,1)+relativedelta(months=1)-relativedelta(days=1),end_date)
                print(f'{symbol} startdate{load_start_date} enddate{load_end_date}')
                try:
                    df=load_rq_data(symbol,exchange,load_start_date,load_end_date,frequency)
                except Exception as e:
                    # print(f'{symbol}未取到{start_date}至{end_date}RQ数据',e)
                    continue
                if len(df):
                    to_clickhouse(dc,table_name,df)
    for symbol_head in ['IH','IF','IC','IM']:
        start_year=max(bond_start_date[symbol_head],start_date).year
        start_month=max(bond_start_date[symbol_head],start_date).month
        for year in range(start_year,to_year+2):
            for month in range(1,13):
                df=pd.DataFrame()
                symbol=symbol_head+str(year-2000)+str(month).zfill(2)
                load_start_date=max(datetime(year,month,1)-relativedelta(years=1),start_date)
                if load_start_date>end_date:
                    continue
                load_end_date=min(datetime(year,month,1)+relativedelta(months=1)-relativedelta(days=1),end_date)
                print(f'{symbol} startdate{load_start_date} enddate{load_end_date}')
                try:
                    df=load_rq_data(symbol,exchange,load_start_date,load_end_date,frequency)
                except Exception as e:
                    # print(f'{symbol}未取到{start_date}至{end_date}RQ数据',e)
                    continue
                if len(df):
                    to_clickhouse(dc,table_name,df)

def save_all_bond_future_history(dc):
    end_date=datetime.now()
    start_date=datetime(2013,9,6)
    for frequency in ['1d','1m','30m']: 
        save_bond_future_889_history(dc,start_date,end_date,frequency)
        save_bond_future_history(dc,start_date,end_date,frequency)

def save_daily_cumulative_bond_future_history(dc):
    end_date=datetime.now()
    start_date=end_date-relativedelta(days=14)
    for frequency in ['1d','1m','30m']:
        save_bond_future_889_history(dc,start_date,end_date,frequency)
        save_bond_future_history(dc,start_date,end_date,frequency)

def calc_start(dc,vt_symbol,interval):
    bond_start_date={'T':datetime(2015,3,20),'TF':datetime(2013,9,6),'TS':datetime(2018,8,17),'TL':datetime(2023,4,21),'IH':datetime(2015,4,16),'IF':datetime(2010,4,16),'IC':datetime(2015,4,16),'IM':datetime(2022,7,22)}
    symbol_head=re.findall(r'[a-zA-Z]+',vt_symbol)[0]
    df=dc.load_bar_data([vt_symbol],interval,bond_start_date[symbol_head],bond_start_date[symbol_head]+relativedelta(days=1))[['datetime','volume','close_price']]
    # print(df)
    return df['close_price'][0]


def calculate_trend(dc,vt_symbols: List[str],intervals:List[str], start: datetime, end: datetime):
    for interval in intervals:
        for vt_symbol in vt_symbols:
            symbol=vt_symbol.split('.')[0]
            df=dc.load_bar_data([vt_symbol],interval,start,end)[['datetime','volume','close_price']]
            df.drop_duplicates(subset=['datetime'],keep='first',inplace=True)
            df.sort_values(by='datetime',ascending=True,inplace=True)
            df['cum_return']=df['close_price']-calc_start(dc,vt_symbol,interval)
            df['cum_return_diff']=df['cum_return'].diff()
            df['cum_return_short_avg']=df['cum_return'].rolling(30).apply(lambda x :np.average(x,weights=list(range(1,31))))
            df['cum_return_long_avg']=df['cum_return'].rolling(200).apply(lambda x :np.average(x,weights=list(range(1,201))))
            df['cum_return_short_avg_diff']=df['cum_return_short_avg'].diff()
            df['cum_return_minus_short_avg']=df['cum_return']-df['cum_return_short_avg']
            df['long_trend']=df.apply(lambda x: x['cum_return'] if (x['cum_return_short_avg_diff']>0)and(x['cum_return_minus_short_avg']>0) else np.nan,axis=1)
            df['short_trend']=df.apply(lambda x: x['cum_return'] if (x['cum_return_short_avg_diff']<0)and(x['cum_return_minus_short_avg']<0) else np.nan,axis=1)
            df.dropna(subset=['cum_return_long_avg'],inplace=True)#第一次全量的时候可以注释掉
            df.set_index('datetime',inplace=True)
            dc.save_factor_df(
                        df=df, # 因子值DataFrame
                        name="bond_future_trend", # 因子名
                        interval=f"{interval.value}", # 周期
                        parameter=f"{symbol}", # 因子参数
                        author="lrj" # 因子作者
                    )#保存不了非数值型内容
            print(min(df.index),'至',max(df.index),f'代码{symbol}频率{interval.value}因子已保存')
            # print(df)
def run_cumulative_index(dc):
    end=datetime.now()
    start=end-relativedelta(years=1)
    vt_symbols=['T889.CFFEX','TF889.CFFEX','TS889.CFFEX','TL889.CFFEX']
    intervals=[Interval.MINUTE_30,Interval.DAILY]
    calculate_trend(dc,vt_symbols,intervals, start, end)

def run_all_index(dc):
    end=datetime.now()
    start=datetime(2013,9,6)
    vt_symbols=['T889.CFFEX','TF889.CFFEX','TS889.CFFEX','TL889.CFFEX']
    intervals=[Interval.MINUTE_30,Interval.DAILY]
    calculate_trend(dc,vt_symbols,intervals, start, end)



if __name__ == '__main__':
    dc = DataCenter()
    save_daily_cumulative_bond_future_history(dc)
    # save_all_bond_future_history(dc)
    run_cumulative_index(dc)
    # run_all_index(dc)
    print('done')

这段代码主要实现了从米筐数据平台(RQData)获取期货数据,将数据存储到ClickHouse数据库,并进行一些趋势计算和因子保存的功能。以下是对代码的详细分析:

代码功能概述

  1. 数据获取:通过米筐数据接口获取不同期货合约的历史行情数据,包括日线、分钟线等不同频率的数据。
  2. 数据存储:将获取到的数据整理后存储到ClickHouse数据库中。
  3. 趋势计算:根据存储在数据库中的数据,计算期货合约的累积收益、短期和长期平均收益等指标,并根据这些指标确定短期和长期趋势。
  4. 因子保存:将计算得到的趋势数据作为因子保存到数据库中。

代码详细分析

模块导入
import warnings
warnings.filterwarnings("ignore")
import rqdatac as rq 
from typing import List
import pandas as pd
import numpy as np
import re
from datetime import datetime, timedelta,time
from dateutil.relativedelta import relativedelta
from vnsw.alpha_research.data_center import DataCenter
from vnpy.trader.constant import Exchange, Interval
from vnpy.trader.setting import SETTINGS
rq.init(username=SETTINGS["datafeed.username"],password=SETTINGS["datafeed.password"])
  • 导入必要的模块,包括处理警告信息的warnings,米筐数据接口rqdatac,类型提示模块typing,数据处理模块pandasnumpy,正则表达式模块re,日期时间处理模块datetimedateutil.relativedelta,以及自定义的数据中心模块DataCentervnpy交易框架中的常量模块ExchangeInterval,以及设置模块SETTINGS
  • 初始化米筐数据接口,使用配置文件中的用户名和密码进行登录。
数据存储函数
def to_clickhouse(dc,table_name,df):
    SAVE_REFERENCE_QUERY = "INSERT INTO {table} VALUES"
    query = SAVE_REFERENCE_QUERY.format(table=table_name)

    # 生成更新时间列
    update = datetime.now()
    df["update"] =update
    # 生成要传参用的DataFrame
    # 写入数据库并返回条数
    try:
        dc.client.insert_dataframe(query, df)
        print('已存储',set(df['symbol']),min(df['interval']),min(df['datetime']),'至',max(df['datetime']))
    except Exception as e:
        print ("报错",e)
  • 该函数用于将数据存储到ClickHouse数据库中。
  • 构造插入数据的SQL查询语句。
  • 为数据添加一个update列,表示数据的更新时间。
  • 尝试将数据插入到数据库中,并打印存储成功的信息。如果插入失败,打印错误信息。
数据获取函数
def load_rq_data(symbols:List[str],exchange:Exchange,start_date:datetime,end_date:datetime,frequency:str)->pd.DataFrame:
    #...
    return df
  • 该函数从米筐数据平台获取指定期货合约的历史行情数据。
  • 根据不同的频率(1d1m),使用rq.get_price方法获取数据。如果频率不是1d1m,则按天循环获取数据。
  • 对获取到的数据进行列名重命名和数据格式整理,添加exchangeinterval等列,并根据频率设置turnoversettlement_price列的值。
数据保存函数
def save_bond_future_889_history(dc,start_date,end_date=datetime.now(),frequency:str='1d'):
    #...
def save_bond_future_history(dc,start_date,end_date=datetime.now(),frequency:str='1d'):
    #...
def save_all_bond_future_history(dc):
    #...
def save_daily_cumulative_bond_future_history(dc):
    #...
  • 这些函数用于保存不同类型的期货历史行情数据到ClickHouse数据库。
  • save_bond_future_889_history保存特定后缀为889的期货合约数据。
  • save_bond_future_history保存具体的期货合约数据,根据合约类型和到期时间循环获取并保存数据。
  • save_all_bond_future_history保存所有期货合约的历史数据,涵盖不同频率。
  • save_daily_cumulative_bond_future_history保存最近14天的期货合约数据,涵盖不同频率。
趋势计算和因子保存函数
def calc_start(dc,vt_symbol,interval):
    #...
    return df['close_price'][0]
def calculate_trend(dc,vt_symbols: List[str],intervals:List[str], start: datetime, end: datetime):
    #...
def run_cumulative_index(dc):
    #...
def run_all_index(dc):
    #...
  • calc_start函数用于计算指定合约在特定时间的起始价格。
  • calculate_trend函数根据获取到的数据计算期货合约的趋势指标,包括累积收益、短期和长期平均收益等,并根据这些指标确定短期和长期趋势。最后将计算得到的因子数据保存到数据库中。
  • run_cumulative_indexrun_all_index函数分别根据不同的时间范围调用calculate_trend函数,计算并保存期货合约的趋势因子。
主程序
if __name__ == '__main__':
    dc = DataCenter()
    save_daily_cumulative_bond_future_history(dc)
    # save_all_bond_future_history(dc)
    run_cumulative_index(dc)
    # run_all_index(dc)
    print('done')
  • 主程序中创建了DataCenter实例,调用save_daily_cumulative_bond_future_history函数保存最近14天的期货合约数据,调用run_cumulative_index函数计算并保存最近一年的期货合约趋势因子。

代码改进建议

  1. 错误处理优化:在数据获取和存储过程中,当前的错误处理较为简单,仅打印错误信息。可以考虑增加更详细的日志记录,以便更好地定位和解决问题。
  2. 代码复用:部分代码存在重复,可以将一些重复的代码片段提取成独立的函数,提高代码的复用性和可维护性。
  3. 性能优化:在数据处理过程中,有些操作可以进行优化,例如在calculate_trend函数中,可以考虑使用更高效的向量化操作来替代apply方法,以提高计算效率。
  4. 注释和文档:增加更多的注释和文档,特别是对于复杂的计算逻辑和业务流程,以提高代码的可读性和可理解性。
  5. 配置管理:将一些硬编码的参数(如合约起始日期、数据库表名等)提取到配置文件中,以便于修改和维护。

通过以上改进,可以使代码更加健壮、高效和易于维护。

为了进行股票量化交易分析,需要构建一个框架来处理获取、处理优化数据,包括模型训练回测。 以下是一个简单的股票量化交易框架: 1. 数据获取:从各种数据源(如API、CSV文件、数据库获取股票价格、财务数据等相关数据。 2. 数据处理:对获取数据进行清洗、转换整合,包括数据清洗、数据格式转换、缺失数据填充等处理。 3. 模型开发优化:使用机器学习深度学习等技术开发优化股票预测交易模型。 4. 模型回测虚拟交易:使用历史数据对模型进行回测,使用虚拟交易进行实时测试优化。 5. 实盘交易:在虚拟交易测试表现良好的情况下,将模型应用到实际的股票交易中。 下面是一个用Python实现的简单股票量化交易框架的示例: ```python import pandas as pd import numpy as np import matplotlib.pyplot as plt # 数据获取 def get_stock_data(symbol, start_date, end_date): # 从API获取股票价格数据 stock_data = get_price_data(symbol, start_date, end_date) # 从CSV文件获取股票财务数据 financial_data = pd.read_csv('financial_data.csv') return stock_data, financial_data # 数据处理 def clean_data(stock_data, financial_data): # 处理股票价格数据 stock_data = stock_data.dropna() stock_data = stock_data[['date', 'close']] # 处理财务数据 financial_data = financial_data.dropna() financial_data = financial_data[['symbol', 'eps', 'p/e']] # 合数据 merged_data = pd.merge(stock_data, financial_data, on='symbol') return merged_data # 模型开发优化 def train_model(merged_data): # 使用线性回归模型预测股票价格 X = merged_data[['eps', 'p/e']] y = merged_data['close'] model = LinearRegression().fit(X, y) return model # 模型回测虚拟交易 def backtest_model(model, stock_data): # 使用历史数据进行回测 predictions = model.predict(stock_data[['eps', 'p/e']]) stock_data['predictions'] = predictions # 计算回报率 stock_data['returns'] = np.log(stock_data['close'] / stock_data['close'].shift(1)) stock_data['strategy_returns'] = np.where(stock_data['predictions'].shift(1) < stock_data['predictions'], stock_data['returns'], -stock_data['returns']) return stock_data # 实盘交易 def trade(model, stock_data): # 在虚拟交易表现良好的情况下,将模型应用到实际交易中 current_price = get_current_price() current_financial_data
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pk_xz123456

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值