使用futuapi把股票K线数据录入mysql数据库中

 富途证券OpenAPI 量化接口,目前已经不能提供,存量中国境内用户还能用,富途行情软件是目前市面上界面最漂亮的行情软件,加上openapi,功能非常强大。

参考官网python版本,终于完成了自选股票K线数据入库。

from futu import *
from Sqlhelper import *
import schedule
class Futuapi:
    def __init__(self):
        """
        初始化函数
        参数: 无
        返回值: 无
        功能描述:
        1. 初始化交易数据上下文环境;
        2. 初始化股票代码列表、开始日期字典、表格列表和周期类型列表。
        """
        self.quote_ctx = OpenQuoteContext(host='127.0.0.1', port=11112)
        self.codes = []#自选股列表
        self.start_date = {}#历史数据获取需要
        self.table_list = ['m1', 'm5', 'm15', 'm30', 'm60', 'day']#K线周期对应表名
        self.type_list = [SubType.K_1M, SubType.K_5M, SubType.K_15M, SubType.K_30M, SubType.K_60M,SubType.K_DAY ]#FUTUAPI的K线周期
        

    def get_user_security(self):#获取自选股列表
        """
        获取用户的自选股列表,并对每只股票进行数据初始化。

    
        函数不接受参数,也不直接返回值,但会对类的内部状态进行更新。
        """
        # 尝试从API接口获取用户自选股票列表
        ret, data = self.quote_ctx.get_user_security("cc")
        if ret == RET_OK and data.shape[0] > 0:
                self.codes = data.to_dict(orient = 'records')   
                 # 将股票代码数据存储为字典格式,每个股票代码对应一条记录
                for i in self.codes:        # 遍历每只股票代码           
                     i['label'] = i['code'].replace(".", "")# 生成股票标签,移除股票代码中的点号
                     dbname = i['label']# 用作数据库名
                     init_db(dbname)# 创建数据库,LABEL为数据库名
                     Creat_table(dbname) # 初始化股票数据表
                     dt = self.get_rehab(i['code'])   #获取复权因子     
                     if len(dt)>0:# 如果成功获取复权因子,则添加到股票信息SEFL.CODES中
                          i['rehab'] = dt    
               # 清空STOCK数据库中历史数据
                delete_all_data_in_stock()
               # 更新股票代码和复权因子信息到数据库
                update_stock_code(self.codes)
                update_stock_rehab(self.codes)
        else:
            print('error:', data)
#获取复权因子['forward_adj_factorA']
    def get_rehab(self,code):#每 30 秒内最多请求 60 次获取复权因子接口。
        """
        获取复权因子数据。
    
        参数:
        code: 股票代码。
    
        返回值:
        rehab_list: 包含复权因子信息的列表,每个元素是一个字典,包括日期和两个复权因子。
        """
        rehab_list = []
        ret, data = self.quote_ctx.get_rehab(code)
        if ret == RET_OK:
            # 成功获取数据,转换为字典列表格式
            rehab = data.to_dict(orient = 'records')
            for i in rehab:               
                 rehab_list.append( {"date":i['ex_div_date'],"factorA":i['forward_adj_factorA'],"factorB":i['forward_adj_factorB']})          
        else:
            print('error:', data) 
        #time.sleep(0.6)自选股数量没有超过50个
        return rehab_list
def request_history_kline(self,Code,Start,End,Ktype):#获取历史 K 线
         """
        获取历史 K 线数据
    
        参数:
        Code: 要查询的股票代码
        Start: 查询的起始时间,格式为 'YYYY-MM-DD HH-MM-SS'
        End: 查询的结束时间,格式为 'YYYY-MM-DD HH-MM-SS'
        Ktype: K 线的类型,例如 [SubType.K_1M, SubType.K_5M, SubType.K_15M, SubType.K_30M, SubType.K_60M,SubType.K_DAY ]#FUTUAPI的K线周期

        返回值:
        如果请求成功,返回一个包含 K 线数据的元组列表,每个元组包含 (时间, 开盘价, 最高价, 最低价, 收盘价)
        如果请求失败,打印错误信息
        """
         ret, data, page_req_key = self.quote_ctx.request_history_kline(code=Code, start=Start, end=End,ktype=Ktype,autype=AuType.QFQ,fields=[KL_FIELD.ALL],max_count=None, page_req_key=None)  # 每页5个,请求第一页
         if ret == RET_OK:
             # 将DataFrame转换为元组列表,方便mysql插入数据库
             data = data[['time_key', 'open', 'high', 'low', 'close']]
             data.rename(columns={'time_key': 'time'}, inplace=True)
             values_list = [tuple(row) for row in data.itertuples(index=False)]
             return values_list
         else:
             print('error:', data)  
def get_date(self):#读取历史K线所需的start end 日期
         """
        获取历史K线数据的起止日期,用于请求最近一段时间的K线数据。
    
        :返回: 无返回值,但会更新实例的start_date字典,其中包含了不同周期K线的最新起始日期。
        """
         End = datetime.now()
         Start = End - timedelta(days=1000)
         End = End.strftime('%Y-%m-%d %H:%M:%S')
         Start = Start.strftime('%Y-%m-%d %H:%M:%S')
         ktype = KLType.K_DAY
         #从沪深300指数的日K中提取
         ret = self.request_history_kline("SZ.399300",Start,End,ktype)
         self.start_date['m1'] = ret[-3][0] # 更新1分钟周期的最新起始日期
         self.start_date['m5'] = ret[-15][0]# 更新5分钟周期的最新起始日期
         self.start_date['m15'] = ret[-45][0] # 更新15分钟周期的最新起始日期
         self.start_date['m30'] = ret[-90][0] # 更新30分钟周期的最新起始日期
         self.start_date['m60'] = ret[-180][0] # 更新60分钟周期的最新起始日期
         self.start_date['day'] = ret[-540][0] # 更新日线周期的最新起始日期
def get_ktype(self,table):
         """
        根据传入的表名,返回相应的K线类型。

        参数:
        - self: 方法的对象引用
        - table: 字符串,表示需要查询的表名,也是K线周期

        返回值:
        - KLType: 枚举类型,表示对应的K线周期
        """
         if table == 'm1':
              return KLType.K_1M
         elif table == 'm5':
              return KLType.K_5M
         elif table == 'm15':
              return KLType.K_15M
         elif table == 'm30':
              return KLType.K_30M
         elif table == 'm60':
              return KLType.K_60M
         elif table == 'day':
              return KLType.K_DAY
def get_klines(self,Code,table):#每 30 秒内最多请求 60 次历史 K 线接口
         """
        请求历史 K 线数据并插入数据库。
    
        每 30 秒内最多请求 60 次历史 K 线接口。
    
        参数:
        - Code: 股票代码,字符串类型。
        - table: 数据表名称,用于存储 K 线数据。
    
        返回值:
        - 无返回值,但会将请求到的 K 线数据插入到指定的数据库表中。
        """
          # 获取当前时间作为结束时间
         End = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
          # 从存储开始日期的字典中获取开始时间
         Start = self.start_date[table]
          # 根据表名获取 K 线类型
         ktype = self.get_ktype(table)
         # 请求历史 K 线数据
         ret = self.request_history_kline(Code,Start,End,ktype)
         # 移除股票代码中的点号,用于数据库表名
         dbname = Code.replace(".", "")
         # 将获取到的 K 线数据插入数据库
         insert_klines(dbname,table,ret)#插入数据
def insert_new_klines(self):
         """
        向数据库中插入新的K线数据。
        遍历self.codes中的所有代码,对于每个代码,首先删除对应数据库中的所有数据,然后根据self.table_list中的表ID获取K线数据并插入。
        不接受任何参数。
        无返回值。
        """
         for code in self.codes:
              dbname = code['code'].replace(".", "") # 从代码中提取数据库名,去掉点号
              delete_all_data_in_db(dbname)#删除所有数据,重新插入
              for table_id in self.table_list:
                   # 获取K线数据
                   self.get_klines(code['code'],table_id)
                   print("插入新数据  " + code['code'] + "  " + table_id )
                   time.sleep(0.6)# 为了防止请求过于频繁,每插入一条数据后暂停0.6秒,每 30 秒内最多50 次,不会超过接口60次限制
def update_m1_klines(self):
          """
        获取指定股票的K线数据(m1分钟线数据)。与实时K线差1分钟,主要是接口限制。
        因为不超过50只自选股,这里不用sleep
        参数:
        self: 类的实例。
    
        返回值:
        无返回值,该函数主要为了获取数据并进行后续操作,不直接返回数据。
        """
          print(datetime.now().strftime('%H:%M:%S') + '   更新1分钟K线数据')
          table = 'm1'# 指定获取的K线数据类型为1分钟线,只更新1分钟数据,其他数据根据1分钟K线合成
          for code in self.codes:
               dbname = code['code'].replace(".", "")
                # 从数据库中获取K线数据
               klines = from_db_get_klines(dbname,table)
               if len(klines) > 0:# 如果获取到数据
                   # 获取最新K线数据的时间作为开始时间,最后一个K
                   starttime = klines[-1][0].strftime('%Y-%m-%d %H:%M:%S')
                   # 获取当前时间作为结束时间
                   end = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
                   # 请求历史K线数据
                   ret = self.request_history_kline(code['code'],starttime,end,self.get_ktype(table))
                    # 如果请求到的数据条数大于1,数据中会包含最后一个K,大于1,说明有新的K线
                   if len(ret) > 1:
                        for j in range(1,len(ret)):# 遍历请求到的数据,从第二条开始
                             if ret[j][0] > starttime: # 如果数据的时间大于数据库中的最后一个K线的时间
                                  # 插入数据到数据库
                                  insert_kline(dbname,table,ret[j])
                                  #历史数据不存在update
def run_update_history(self):
         """
        启动定时任务,每隔30秒执行一次update_m1_klines方法。

        无参数
        无返回值
        """
         self.get_user_security()#获取自选股列表,更新stock库中的代码列表和复权因子数据
         self.get_date()#获取开始时间
         self.insert_new_klines()#第一次更新所有周期数据,更新前清空所有数据
        # 每隔30秒执行一次update_m1_klines方法,只更新1分钟历史K线,与实时差1分钟
         schedule.every(30).seconds.do(self.update_m1_klines)
         # 无限循环,确保定时任务可以持续执行
         while True:
             # 运行所有可以运行的任务
             schedule.run_pending()
             time.sleep(1)  # 防止CPU占用过高            
    

# 示例用法
if __name__ == "__main__":
    f = Futuapi()
    f.run_update_history()
    

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值