Python讀取通達信本地數(shù)據(jù)

獲取內(nèi)容

股票名稱、縮寫闻鉴、領(lǐng)域及K線(日 周 月 季 年)

import os
import struct
import pandas as pd


# 負責讀取本地通達信數(shù)據(jù)
class TDXLoader:
    def __init__(self):
        # TDX_DIR 為通達信根目錄
        self.TDX_DIR = os.environ.get("Tdx")
        self.__base_all = self._get_base_all()

    def resolve(self, *args, **kwargs):
        return os.path.join(self.TDX_DIR, *args, **kwargs)

    # 獲取行業(yè)數(shù)據(jù)
    def _get_tdxhy(self):
        tdxhy_path = self.resolve(r"T0002\hq_cache\tdxhy.cfg")
        names = "market symbol industry_code idontcare1 idontcare2 industry_second_code".split()
        usecols = "market symbol industry_code industry_second_code".split()
        tdxhy = pd.read_csv(
            tdxhy_path,
            sep="|",
            names=names,
            usecols=usecols,
            dtype={"symbol": str},
        )
        return tdxhy

    # 行業(yè)代碼碼值
    def _get_incon(self):
        incon_path = self.resolve(r"incon.dat")
        incon = pd.read_csv(incon_path, encoding="gb2312", names=["index"])
        fx0 = lambda x: x.split("|")[0] if "|" in x else ""
        incon["industry_code"] = incon["index"].apply(fx0)
        fx1 = lambda x: x.split("|")[1] if "|" in x else ""
        incon["industry_name"] = incon["index"].apply(fx1)
        usecols = ["industry_code", "industry_name"]
        return incon[usecols]

    # 股票代碼對應(yīng)拼音縮寫
    def _read_tnf(self, path):
        market = path.split(".")[0][-3:]
        with open(path, "rb") as f:
            buff = f.read()

        data = buff[50:]
        l = len(data) // 314
        fx = lambda x: str(x, encoding="gbk").strip("\x00")
        sm = {"szm": ("00", "30"), "shm": ("60", "68")}

        stocks = []
        for x in [data[i * 314 : (i + 1) * 314] for i in range(l)]:
            code = fx(x[:6])
            if code.startswith(sm[market]):
                name = fx(x[23:41])
                shortcode = fx(x[285:293])

                stocks += [[code, name, shortcode]]
        return stocks

    # 股票K線數(shù)據(jù)源文件
    def _get_szshm(self):
        szm_path = self.resolve(r"T0002\hq_cache\szm.tnf")
        shm_path = self.resolve(r"T0002\hq_cache\shm.tnf")

        szm = self._read_tnf(szm_path)
        shm = self._read_tnf(shm_path)

        stocks = pd.DataFrame(szm + shm, columns=["symbol", "name", "shortcode"])
        return stocks

    # 整合基本數(shù)據(jù)
    def _get_base_all(self):
        tdxhy = self._get_tdxhy()
        incon = self._get_incon()
        szshm = self._get_szshm()

        base = pd.merge(szshm, tdxhy, how="left", on="symbol")
        base = pd.merge(base, incon, how="left", on="industry_code")
        base = pd.merge(
            base,
            incon,
            how="left",
            left_on="industry_second_code",
            right_on="industry_code",
        )

        fx = lambda x: ".sh" if x else ".sz"
        base["ts_code"] = base["symbol"] + base["market"].apply(fx)

        base.rename(
            columns={
                "industry_name_x": "industry_name",
                "industry_name_y": "industry_detail",
            },
            inplace=True,
        )
        usecols = "ts_code symbol name shortcode industry_name industry_detail".split()
        return base[usecols]

    # 讀取K線源文件
    def _read_kline(self, filepath):
        with open(filepath, "rb") as f:
            usecols = "trade_date open high low close amount vol openinterest".split()
            buffers = []
            while True:
                buffer = f.read(32)
                if not buffer:
                    break
                buffer = struct.unpack("lllllfll", buffer)
                buffers.append(buffer)
            kline = pd.DataFrame(buffers, columns=usecols)

        kline["trade_date"] = kline["trade_date"].astype(str)

        price_columns = ["open", "high", "low", "close"]
        kline[price_columns] = kline[price_columns].apply(lambda x: x / 100)
        return kline

    # 獲取基本數(shù)據(jù)
    def get_base_all(self):
        return self.__base_all

    # 獲取日K線數(shù)據(jù)
    def get_kline_daily(self, ts_code):
        filename = ts_code.split(".")[1] + ts_code.split(".")[0] + ".day"
        filepath = self.resolve("vipdoc", ts_code.split(".")[1], "lday", filename)
        kline = self._read_kline(filepath)
        kline["ts_code"] = ts_code
        kline.index = pd.to_datetime(kline["trade_date"])
        kline.index.name = "index"
        kline = kline.rename(columns={"vol": "volume"})
        usecols = (
            "ts_code trade_date open high low close amount volume openinterest".split()
        )
        return kline[usecols]


if __name__ == "__main__":
    loader = TDXLoader()
    # 獲取所有股票基本數(shù)據(jù)
    base_all = loader.get_base_all()
    # 獲取單股日K線數(shù)據(jù)
    kline = loader.get_kline_daily("600645.sh")
    print(kline)

走緩存,并加工出K線的各個周期

單單運行腳本緩存是無效的睁枕,需要放在Web服務(wù)或桌面應(yīng)用中

from store.loader import TDXLoader as Loader
from cacheout import LFUCache

from loguru import logger as log


# 負責緩存
class Cache(object):
    def __init__(self):
        self.__loader = Loader()
        self.cache = LFUCache()

        self.rule = {
            "ts_code": "last",
            "trade_date": "last",
            "open": "first",
            "high": "max",
            "low": "min",
            "close": "last",
            "volume": "sum",
            "openinterest": "last",
        }

    # 從緩存獲取日K線盗胀,沒有緩存就從Loader讀取
    def _get_kline_daily(self, ts_code):
        if self.cache.has(ts_code):
            kline = self.cache.get(ts_code)
        else:
            kline = self.__loader.get_kline_daily(ts_code)
            self.cache.set(ts_code, kline)
            log.info(f"{ts_code} K線數(shù)據(jù)已緩存")
        return kline

    # 按 日 周 月 季 年 獲取K線數(shù)據(jù)艘蹋,對應(yīng)周期為 D W M Q A。day week month quarter annual
    def _get_kline_by_period(self, ts_code, period="D"):
        kline = self._get_kline_daily(ts_code)

        kline = kline.resample(period).agg(self.rule).dropna()
        kline = kline.sort_values(by="trade_date", ascending=False)
        kline = kline.reset_index(drop=True)

        return kline

    # 按天數(shù)分割獲取K線數(shù)據(jù)票灰,days等于30則代表30天為一個周期
    def _get_kline_by_days(self, ts_code, days=1):
        kline = self._get_kline_daily(ts_code)

        kline = kline.sort_values(by="trade_date", ascending=False)
        kline = kline.reset_index(drop=True).sort_values(by="trade_date")
        kline = kline.groupby(lambda x: x // days).agg(self.rule)
        kline = kline.sort_values(by="trade_date", ascending=False)

        return kline

    # 獲取基本數(shù)據(jù)的函數(shù)女阀,傳股票代碼進來就獲取一只股票的,不傳參就獲取所有股票的
    def get_base(self, ts_code=None):
        data = self.__loader.get_base_all()
        if ts_code:
            base = data[data["ts_code"] == ts_code]
        else:
            base = data
        return base

    # 整合 _get_kline_by_period 和 _get_kline_by_days
    def get_kline(self, ts_code, param):
        if isinstance(param, int):
            return self._get_kline_by_days(ts_code, days=param)
        else:
            return self._get_kline_by_period(ts_code, period=param)


datas = Cache()


if __name__ == "__main__":
    # 獲取所有股票基本數(shù)據(jù)
    base_all = datas.get_base()
    # 獲取單股基本數(shù)據(jù)
    base_all = datas.get_base("600571.sh")
    # 獲取單股日線數(shù)據(jù)
    kline = datas.get_kline("600571.sh", "D")
    # 獲取單股周線數(shù)據(jù)
    kline = datas.get_kline("600571.sh", "W")
    # 獲取單股月線數(shù)據(jù)
    kline = datas.get_kline("600571.sh", "M")
    # 獲取單股季線數(shù)據(jù)
    kline = datas.get_kline("600571.sh", "Q")
    # 獲取單股年線數(shù)據(jù)
    kline = datas.get_kline("600571.sh", "A")
    # 獲取單股以5天為周期的數(shù)據(jù)
    kline = datas.get_kline("600571.sh", 5)
    # 獲取單股以30天為周期的數(shù)據(jù)
    kline = datas.get_kline("600571.sh", 30)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末屑迂,一起剝皮案震驚了整個濱河市浸策,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌屈糊,老刑警劉巖的榛,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異逻锐,居然都是意外死亡夫晌,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門昧诱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晓淀,“玉大人,你說我怎么就攤上這事盏档⌒钻” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵蜈亩,是天一觀的道長懦窘。 經(jīng)常有香客問我,道長稚配,這世上最難降的妖魔是什么畅涂? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮道川,結(jié)果婚禮上午衰,老公的妹妹穿的比我還像新娘。我一直安慰自己冒萄,他們只是感情好臊岸,可當我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著尊流,像睡著了一般帅戒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上崖技,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天逻住,我揣著相機與錄音施流,去河邊找鬼。 笑死鄙信,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的忿晕。 我是一名探鬼主播装诡,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼践盼!你這毒婦竟也來了鸦采?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤咕幻,失蹤者是張志新(化名)和其女友劉穎渔伯,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肄程,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡锣吼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蓝厌。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片玄叠。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖拓提,靈堂內(nèi)的尸體忽然破棺而出读恃,到底是詐尸還是另有隱情,我是刑警寧澤代态,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布寺惫,位于F島的核電站,受9級特大地震影響蹦疑,放射性物質(zhì)發(fā)生泄漏西雀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一必尼、第九天 我趴在偏房一處隱蔽的房頂上張望蒋搜。 院中可真熱鬧,春花似錦判莉、人聲如沸豆挽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽帮哈。三九已至,卻和暖如春锰镀,著一層夾襖步出監(jiān)牢的瞬間娘侍,已是汗流浹背咖刃。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留憾筏,地道東北人嚎杨。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像氧腰,于是被迫代替她去往敵國和親枫浙。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內(nèi)容