161 lines
5.8 KiB
Python
161 lines
5.8 KiB
Python
"""
|
||
Script Name:
|
||
Description: 从富途获取历史K线。通过不同变量,可以获取不复权、前复权、后复权等数据。
|
||
参考地址: https://openapi.futunn.com/futu-api-doc/quote/request-history-kline.html
|
||
|
||
Author: [Your Name]
|
||
Created Date: YYYY-MM-DD
|
||
Last Modified: YYYY-MM-DD
|
||
Version: 1.0
|
||
|
||
Modification History:
|
||
- YYYY-MM-DD [Your Name]:
|
||
- YYYY-MM-DD [Your Name]:
|
||
- YYYY-MM-DD [Your Name]:
|
||
"""
|
||
|
||
import pymysql
|
||
import time
|
||
import logging
|
||
from futu import *
|
||
from datetime import datetime, timedelta
|
||
import config
|
||
|
||
config.setup_logging()
|
||
|
||
# 连接 MySQL
|
||
connection = pymysql.connect(**config.db_config)
|
||
|
||
# 复权类型,不复权
|
||
# selected_autype = AuType.NONE
|
||
# selected_table = "hs300_his_kline_none"
|
||
|
||
# 复权类型,后复权
|
||
selected_autype = AuType.HFQ
|
||
selected_table = "hs300_his_kline_hfq"
|
||
|
||
# 复权类型,默认为 AuType.QFQ ,即前复权
|
||
# selected_autype = AuType.QFQ
|
||
# selected_table = "hs300_qfq_his"
|
||
|
||
# 获取当前日期
|
||
end_date = datetime.now().strftime('%Y-%m-%d')
|
||
# 计算 start_date 为当前日期减去10年,再加一天
|
||
start_date = (datetime.now() - timedelta(days=365*10-1)).strftime('%Y-%m-%d')
|
||
|
||
# 定义插入数据的函数
|
||
def insert_data(connection, data, s_table=selected_table):
|
||
try:
|
||
with connection.cursor() as cursor:
|
||
for index, row in data.iterrows():
|
||
sql = f"""
|
||
INSERT INTO {s_table} (code, name, time_key, open, close, high, low, pe_ratio, turnover_rate, volume, turnover, change_rate, last_close)
|
||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||
ON DUPLICATE KEY UPDATE
|
||
name = VALUES(name),
|
||
open = VALUES(open),
|
||
close = VALUES(close),
|
||
high = VALUES(high),
|
||
low = VALUES(low),
|
||
pe_ratio = VALUES(pe_ratio),
|
||
turnover_rate = VALUES(turnover_rate),
|
||
volume = VALUES(volume),
|
||
turnover = VALUES(turnover),
|
||
change_rate = VALUES(change_rate),
|
||
last_close = VALUES(last_close)
|
||
"""
|
||
cursor.execute(sql, (
|
||
row['code'], row['name'], row['time_key'], row['open'], row['close'],
|
||
row['high'], row['low'], row['pe_ratio'], row['turnover_rate'],
|
||
row['volume'], row['turnover'], row['change_rate'], row['last_close']
|
||
))
|
||
connection.commit()
|
||
except pymysql.MySQLError as e:
|
||
logging.error(f"Error occurred while inserting data: {e}")
|
||
print(f"Error occurred while inserting data: {e}")
|
||
|
||
# 获取 hs300 表中的所有股票代码
|
||
def get_hs300_codes():
|
||
with connection.cursor() as cursor:
|
||
cursor.execute("SELECT code FROM hs300 ")
|
||
return cursor.fetchall()
|
||
|
||
def stat_growth(s_autype = selected_autype, s_table = selected_table, s_start = start_date, s_end = end_date):
|
||
# 初始化 futu 行情连接
|
||
quote_ctx = OpenQuoteContext(host='127.0.0.1', port=11111)
|
||
|
||
try:
|
||
hs300_codes = get_hs300_codes()
|
||
for code_row in hs300_codes:
|
||
code = code_row[0] # 从数据库行中提取 code
|
||
|
||
# 获取历史 K 线数据,设置分页请求
|
||
ret, data, page_req_key = quote_ctx.request_history_kline(code, autype=s_autype, start=s_start, end=s_end, max_count=500)
|
||
if ret == RET_OK:
|
||
logging.info(f"成功获取 {code} 的第一页数据,共 {len(data)} 行")
|
||
print(f"成功获取 {code} 的第一页数据,共 {len(data)} 行")
|
||
|
||
# 插入第一页数据
|
||
insert_data(connection, data, s_table)
|
||
else:
|
||
logging.error(f"获取 {code} 的数据失败: {data}")
|
||
print(f"获取 {code} 的数据失败: {data}")
|
||
|
||
# 分页拉取
|
||
while page_req_key is not None:
|
||
time.sleep(1) # 休眠 5 秒
|
||
ret, data, page_req_key = quote_ctx.request_history_kline(code, autype=s_autype, start=s_start, end=s_end, max_count=500, page_req_key=page_req_key)
|
||
if ret == RET_OK:
|
||
logging.info(f"成功获取 {code} 的分页数据,共 {len(data)} 行")
|
||
print(f"成功获取 {code} 的分页数据,共 {len(data)} 行")
|
||
|
||
# 插入分页数据
|
||
insert_data(connection, data, s_table)
|
||
else:
|
||
logging.error(f"分页数据获取失败: {data}")
|
||
print(f"分页数据获取失败: {data}")
|
||
|
||
# 每次获取完一个股票的数据后,休眠 5 秒
|
||
time.sleep(2)
|
||
|
||
finally:
|
||
quote_ctx.close() # 关闭 futu 连接
|
||
connection.close() # 关闭 MySQL 连接
|
||
|
||
def print_help():
|
||
print("Usage: python script.py type end_date start_date")
|
||
print("type: qfq|hfq|none, default for none")
|
||
print('start_date: yyyy-mm-dd, default for end_date - 10 years ')
|
||
print('end_date: yyyy-mm-dd, default for current date ')
|
||
|
||
def main():
|
||
type = selected_autype
|
||
table = selected_table
|
||
start = start_date
|
||
end = end_date
|
||
|
||
args_num = len(sys.argv)
|
||
if args_num > 1 :
|
||
if sys.argv[1] == 'none':
|
||
type = AuType.NONE
|
||
table = "hs300_his_kline_none"
|
||
elif sys.argv[1] == 'qfq':
|
||
type = AuType.QFQ
|
||
table = "hs300_qfq_his"
|
||
elif sys.argv[1] == 'hfq':
|
||
type = AuType.HFQ
|
||
table = "hs300_his_kline_hfq"
|
||
else:
|
||
print_help()
|
||
exit(1)
|
||
if args_num > 2 :
|
||
end = sys.argv[2]
|
||
if args_num > 3 :
|
||
start = sys.argv[3]
|
||
|
||
print(f'fetching his kline... type: {type}, table: {table}, start: {start}, end: {end}\n\n')
|
||
stat_growth(type, table, start, end)
|
||
|
||
if __name__ == '__main__':
|
||
main()
|