177 lines
5.1 KiB
Python
177 lines
5.1 KiB
Python
|
import struct
|
|||
|
from pathlib import Path
|
|||
|
|
|||
|
import pandas as pd
|
|||
|
|
|||
|
"""
|
|||
|
通达信操作工具类
|
|||
|
"""
|
|||
|
|
|||
|
|
|||
|
class TdxUtil:
|
|||
|
SECURITY_EXCHANGE = ["sz", "sh"]
|
|||
|
SECURITY_COEFFICIENT = {"SH_A_STOCK": [0.01, 0.01], "SH_B_STOCK": [0.001, 0.01], "SH_INDEX": [0.01, 1.0],
|
|||
|
"SH_FUND": [0.001, 1.0], "SH_BOND": [0.001, 1.0], "SZ_A_STOCK": [0.01, 0.01],
|
|||
|
"SZ_B_STOCK": [0.01, 0.01], "SZ_INDEX": [0.01, 1.0], "SZ_FUND": [0.001, 0.01],
|
|||
|
"SZ_BOND": [0.001, 0.01]}
|
|||
|
SECURITY_TYPE = ["SH_A_STOCK", "SH_B_STOCK", "SH_INDEX", "SH_FUND", "SH_BOND", "SZ_A_STOCK", "SZ_B_STOCK",
|
|||
|
"SZ_INDEX", "SZ_FUND", "SZ_BOND"]
|
|||
|
|
|||
|
def __init__(self, tdx_path: str):
|
|||
|
self.f_name = None
|
|||
|
self.path = tdx_path
|
|||
|
# 通达信自选股路径
|
|||
|
self.zxg_path = tdx_path + "\\T0002\\blocknew\\ZXG.blk"
|
|||
|
# 上证日线
|
|||
|
self.lday_sz_path = tdx_path + "\\vipdoc\\sz\\lday\\"
|
|||
|
# 沪深日线
|
|||
|
self.lday_sh_path = tdx_path + "\\vipdoc\\sh\\lday\\"
|
|||
|
|
|||
|
def set_zxg_file(self, cont: pd):
|
|||
|
"""
|
|||
|
通达信自选股写入
|
|||
|
:param cont:
|
|||
|
:return:
|
|||
|
"""
|
|||
|
# 将 DataFrame 内容逐行写入文本文件
|
|||
|
with open(self.zxg_path, "w") as file:
|
|||
|
for item in cont:
|
|||
|
stock_code = str(item)
|
|||
|
code = stock_code.split(".")[0]
|
|||
|
if len(code) > 1:
|
|||
|
if stock_code.startswith(('50', '51', '60', '688', '73', '90', '110', '113', '132', '204', '78')):
|
|||
|
code = '1' + stock_code
|
|||
|
if stock_code.startswith(('00', '13', '18', '15', '16', '18', '20', '30', '39', '115', '1318')):
|
|||
|
code = '0' + stock_code
|
|||
|
file.write(code + '\n')
|
|||
|
# 关闭文件
|
|||
|
file.close()
|
|||
|
|
|||
|
def get_zxg_file(self):
|
|||
|
"""
|
|||
|
读取通达信自选股
|
|||
|
:return:
|
|||
|
"""
|
|||
|
f = open(self.zxg_path, 'r')
|
|||
|
z = f.read()
|
|||
|
f.close()
|
|||
|
return z
|
|||
|
|
|||
|
def get_tdx_stock_data(self, code=None, freq=None, market=None):
|
|||
|
"""
|
|||
|
获取K线数据(日线,1分钟线,5分钟线,30分钟线)
|
|||
|
:param code: 股票代码
|
|||
|
:param freq: 分钟数据,1:代表1分钟,5:代表5分钟
|
|||
|
:param market: 上海证券交易所: sh, 深证证券交易所: sz, 北京证券交易所: bj
|
|||
|
:return:
|
|||
|
"""
|
|||
|
# 获取全部的数据
|
|||
|
if code is None:
|
|||
|
return self.get_all_stock()
|
|||
|
if freq is None:
|
|||
|
return self.get_day_k(code, market)
|
|||
|
else:
|
|||
|
return self.get_freq_k(code, market, freq)
|
|||
|
|
|||
|
def get_all_stock(self):
|
|||
|
"""
|
|||
|
获取全部股票
|
|||
|
:return:
|
|||
|
"""
|
|||
|
codes = []
|
|||
|
for market in self.SECURITY_EXCHANGE:
|
|||
|
files = Path(f'\\vipdoc\\{market}\\lday\\')
|
|||
|
for file in files.iterdir():
|
|||
|
if not file.is_file():
|
|||
|
continue
|
|||
|
tdx_code = file.name.split(".")[0]
|
|||
|
market = tdx_code[:2]
|
|||
|
code = tdx_code[2:]
|
|||
|
res = self.get_security_type(code=code, market=market)
|
|||
|
filter_stock = ["SZ_A_STOCK", "SH_A_STOCK"]
|
|||
|
if res not in filter_stock:
|
|||
|
continue
|
|||
|
codes.append(code)
|
|||
|
return codes
|
|||
|
|
|||
|
def get_day_k(self, code, market):
|
|||
|
security_type = self.get_security_type(code, market)
|
|||
|
if security_type not in self.SECURITY_TYPE:
|
|||
|
print("Unknown security type !\n")
|
|||
|
raise NotImplementedError
|
|||
|
if security_type == "SZ_A_STOCK":
|
|||
|
self.f_name = f"{self.lday_sz_path}sz{code}.day"
|
|||
|
if security_type == "SH_A_STOCK":
|
|||
|
self.f_name = f"{self.lday_sh_path}sh{code}.day"
|
|||
|
print(self.f_name)
|
|||
|
df = pd.DataFrame(columns=['trade_date', 'open', 'high', 'low', 'close', 'amount', 'volume'])
|
|||
|
file_path = Path(self.f_name)
|
|||
|
coefficient = [0.01, 0.01]
|
|||
|
if not file_path.is_file():
|
|||
|
raise f"{self.f_name} 不是一个文件!"
|
|||
|
content = file_path.read_bytes()
|
|||
|
record_struct = struct.Struct('<IIIIIfII')
|
|||
|
print(len(content), record_struct.size)
|
|||
|
for offset in range(0, len(content), record_struct.size):
|
|||
|
row = record_struct.unpack_from(content, offset)
|
|||
|
t_date = str(row[0])
|
|||
|
# datestr = t_date[:4] + "-" + t_date[4:6] + "-" + t_date[6:]
|
|||
|
close = row[4] * coefficient[0]
|
|||
|
open = row[1] * coefficient[0]
|
|||
|
new_row = [
|
|||
|
t_date,
|
|||
|
open,
|
|||
|
row[2] * coefficient[0],
|
|||
|
row[3] * coefficient[0],
|
|||
|
close,
|
|||
|
row[5],
|
|||
|
row[6] * coefficient[1],
|
|||
|
]
|
|||
|
df.loc[len(df)] = new_row
|
|||
|
return df
|
|||
|
|
|||
|
def get_freq_k(self, code, market, freq):
|
|||
|
pass
|
|||
|
|
|||
|
def get_security_type(self, code, name=None, market=None):
|
|||
|
exchange = str(market).lower()
|
|||
|
code_head = code[:2]
|
|||
|
if name is not None:
|
|||
|
if 'ST' in name or '*' in name:
|
|||
|
return None
|
|||
|
if exchange == self.SECURITY_EXCHANGE[0]:
|
|||
|
if code_head in ["00", "30"]:
|
|||
|
return "SZ_A_STOCK"
|
|||
|
elif code_head in ["20"]:
|
|||
|
return "SZ_B_STOCK"
|
|||
|
elif code_head in ["39"]:
|
|||
|
return "SZ_INDEX"
|
|||
|
elif code_head in ["15", "16"]:
|
|||
|
return "SZ_FUND"
|
|||
|
elif code_head in ["10", "11", "12", "13", "14"]:
|
|||
|
return "SZ_BOND"
|
|||
|
elif exchange == self.SECURITY_EXCHANGE[1]:
|
|||
|
if code_head in ["60", "68"]: # 688XXX科创板
|
|||
|
return "SH_A_STOCK"
|
|||
|
elif code_head in ["90"]:
|
|||
|
return "SH_B_STOCK"
|
|||
|
elif code_head in ["00", "88", "99"]:
|
|||
|
return "SH_INDEX"
|
|||
|
elif code_head in ["50", "51"]:
|
|||
|
return "SH_FUND"
|
|||
|
elif code_head in ["01", "10", "11", "12", "13", "14", "20"]:
|
|||
|
return "SH_BOND"
|
|||
|
else:
|
|||
|
# 如果没有标识,只返回A股 TODO 不要创业板
|
|||
|
if code_head in ["00"]:
|
|||
|
return "SZ_A_STOCK"
|
|||
|
elif code_head in ["60"]:
|
|||
|
return "SH_A_STOCK"
|
|||
|
else:
|
|||
|
return None
|
|||
|
|
|||
|
|
|||
|
if __name__ == '__main__':
|
|||
|
tdx = TdxUtil("D:\\new_tdx")
|
|||
|
print(tdx.get_tdx_stock_data("002448"))
|