feat: merge datetime fields in DataFrame output, hide MinuteBar internal fields

- K-line: daily+ periods output 'date' only, minute periods output 'datetime'
- Transactions (tick-by-tick): combine date param + hour/minute into 'datetime'
- XdxrRecord, HistoricalFundFlow: year/month/day merged to 'date'
- MinuteBar: rename unknown_1 to _unknown_1 (hidden from DataFrame)
- MinuteBar: add datetime column computed from bar index (A-share 240-bar pattern)
- get_minute_time_data: use history endpoint only (current-day endpoint broken in pytdx too)
- Update all examples to reflect new DataFrame column names
This commit is contained in:
Justin Gu
2026-05-22 04:19:07 +08:00
parent 0d7f7aead1
commit 00825eb24a
31 changed files with 720 additions and 663 deletions
+176 -165
View File
@@ -4,132 +4,175 @@ import asyncio
import struct
from unittest.mock import patch
import pandas as pd
from easy_tdx import AsyncTdxClient, Market, TdxClient
from easy_tdx.client import _classify_fund_flow
from easy_tdx.commands.minute_time import (
GetHistoryMinuteTimeDataCmd,
)
from easy_tdx.commands.security_bars import GetSecurityBarsCmd
from easy_tdx.commands.security_list import GetSecurityListCmd
from easy_tdx.commands.security_quotes import GetSecurityQuotesCmd
from easy_tdx.commands.transaction import (
GetHistoryTransactionDataCmd,
GetTransactionDataCmd,
)
from easy_tdx.models.bar import SecurityBar
from easy_tdx.models.quote import SecurityQuote
from easy_tdx.models.security import SecurityInfo
from easy_tdx.models.stats import HistoricalFundFlow
from easy_tdx.models.timeseries import MinuteBar
from easy_tdx.models.timeseries import TransactionRecord
from easy_tdx.models.timeseries import MinuteBar, TransactionRecord
@patch("easy_tdx.client.TdxConnection")
def test_get_fund_flow_logic(_mock_conn_cls):
"""测试资金流分类计算逻辑。"""
client = TdxClient("127.0.0.1")
# 构造模拟 Tick 数据
mock_recs = [
TransactionRecord(10, 0, 100.0, 101, 0, 0), # super_in (100*101*100 = 101w)
TransactionRecord(10, 1, 10.0, 250, 1, 0), # large_out (10*250*100 = 25w)
TransactionRecord(10, 2, 10.0, 10, 0, 0), # small_in (10*10*100 = 1w)
TransactionRecord(10, 0, 100.0, 101, 0, 0), # super_in
TransactionRecord(10, 1, 10.0, 250, 1, 0), # large_out
TransactionRecord(10, 2, 10.0, 10, 0, 0), # small_in
]
with patch.object(TdxClient, "get_transaction_data", return_value=mock_recs):
def mock_execute(cmd):
if isinstance(cmd, GetTransactionDataCmd):
return mock_recs
return []
with patch.object(TdxClient, "_execute", side_effect=mock_execute):
flow = client.get_fund_flow(Market.SH, "600000")
assert flow.super_in == 1010000.0
assert flow.large_out == 250000.0
assert flow.small_in == 10000.0
assert flow.main_net_inflow == 1010000.0 - 250000.0
assert isinstance(flow, pd.DataFrame)
assert flow["super_in"].iloc[0] == 1010000.0
assert flow["large_out"].iloc[0] == 250000.0
assert flow["small_in"].iloc[0] == 10000.0
def test_classify_fund_flow_exact_thresholds_use_lower_bucket():
"""恰好命中阈值时,应落入较低一档。"""
flow = _classify_fund_flow([
TransactionRecord(10, 0, 100.0, 100, 0, 0), # 100w -> large
TransactionRecord(10, 1, 100.0, 20, 0, 0), # 20w -> medium
TransactionRecord(10, 2, 100.0, 4, 0, 0), # 4w -> small
])
flow = _classify_fund_flow(
[
TransactionRecord(10, 0, 100.0, 100, 0, 0), # 100w -> large
TransactionRecord(10, 1, 100.0, 20, 0, 0), # 20w -> medium
TransactionRecord(10, 2, 100.0, 4, 0, 0), # 4w -> small
]
)
assert flow.super_in == 0.0
assert flow.large_in == 1000000.0
assert flow.medium_in == 200000.0
assert flow.small_in == 40000.0
@patch("easy_tdx.client.TdxConnection")
def test_get_security_list_all_filtering(_mock_conn_cls):
"""测试三市 A 股过滤与行业挂载逻辑。"""
client = TdxClient("127.0.0.1")
# 模拟行业配置 tdxhy.cfg
industry_cfg = b"1|600000|T01|||X01\n0|000001|T02|||X02\n2|830000|T03|||X03"
# 模拟各市场返回
def mock_get_list(market, start):
if market == Market.SH:
return [
SecurityInfo(Market.SH, "600000", "SH_A", 100, 2, 10.0),
SecurityInfo(Market.SH, "999999", "INDEX", 100, 2, 3000.0), # 应被过滤
]
if market == Market.SZ:
return [SecurityInfo(Market.SZ, "000001", "SZ_A", 100, 2, 10.0)]
if market == Market.BJ:
return [SecurityInfo(Market.BJ, "830000", "BJ_A", 100, 2, 10.0)]
def mock_execute(cmd):
if isinstance(cmd, GetSecurityListCmd):
if cmd.market == Market.SH:
return [
SecurityInfo(Market.SH, "600000", "SH_A", 100, 2, 10.0),
SecurityInfo(Market.SH, "999999", "INDEX", 100, 2, 3000.0),
]
if cmd.market == Market.SZ:
return [SecurityInfo(Market.SZ, "000001", "SZ_A", 100, 2, 10.0)]
return []
return []
with patch.object(TdxClient, "get_report_file", return_value=industry_cfg), \
patch.object(TdxClient, "get_security_count", return_value=1), \
patch.object(TdxClient, "get_security_list", side_effect=mock_get_list):
all_stocks = client.get_security_list_all()
with (
patch.object(TdxClient, "_execute", side_effect=mock_execute),
patch.object(TdxClient, "get_report_file", return_value=industry_cfg),
patch.object(TdxClient, "get_security_count", return_value=1),
):
all_stocks = client.get_security_list_all(pages=1)
# 预期只有 SH 和 SZ,BJ 已在扫描中降级移除
assert isinstance(all_stocks, pd.DataFrame)
assert len(all_stocks) == 2
codes = [s.code for s in all_stocks]
codes = all_stocks["code"].tolist()
assert "600000" in codes
assert "000001" in codes
assert "830000" not in codes
s0 = next(s for s in all_stocks if s.code == "600000")
assert s0.industry_tdx == "T01"
assert "830000" not in codes
row = all_stocks[all_stocks["code"] == "600000"].iloc[0]
assert row["industry_tdx"] == "T01"
@patch("easy_tdx.client.TdxConnection")
def test_get_market_stat_mapping(_mock_conn_cls):
"""测试市场统计字段映射。"""
client = TdxClient("127.0.0.1")
mock_quote = SecurityQuote(
Market.SH, "880005",
price=3000.0, # up
pre_close=2000.0, # down
open=0,
high=5500.0, # total
low=500.0, # neutral (low=500 -> neutral_count=500)
vol=1000000.0, cur_vol=0, amount=50000000.0,
s_vol=0, b_vol=0, active1=0, active2=0,
bid1=0, bid_vol1=0, bid2=0, bid_vol2=0, bid3=0, bid_vol3=0,
bid4=0, bid_vol4=0, bid5=0, bid_vol5=0,
ask1=0, ask_vol1=0, ask2=0, ask_vol2=0, ask3=0, ask_vol3=0,
ask4=0, ask_vol4=0, ask5=0, ask_vol5=0,
rise_speed=0, limit_up=0, limit_down=0
Market.SH,
"880005",
price=3000.0, # up = int(price)
pre_close=0,
open=2000.0, # down = int(open)
high=5500.0, # total = int(high)
low=500.0, # neutral = int(low)
vol=1000000.0,
cur_vol=0,
amount=50000000.0,
s_vol=0,
b_vol=0,
active1=0,
active2=0,
bid1=0,
bid_vol1=0,
bid2=0,
bid_vol2=0,
bid3=0,
bid_vol3=0,
bid4=0,
bid_vol4=0,
bid5=0,
bid_vol5=0,
ask1=0,
ask_vol1=0,
ask2=0,
ask_vol2=0,
ask3=0,
ask_vol3=0,
ask4=0,
ask_vol4=0,
ask5=0,
ask_vol5=0,
rise_speed=0,
limit_up=0,
limit_down=0,
)
with patch.object(TdxClient, "get_security_quotes", return_value=[mock_quote]):
def mock_execute(cmd):
if isinstance(cmd, GetSecurityQuotesCmd):
return [mock_quote]
return []
with patch.object(TdxClient, "_execute", side_effect=mock_execute):
stat = client.get_market_stat()
assert stat.up_count == 3000
assert stat.down_count == 2000
assert stat.neutral_count == 500
assert stat.total_count == 5500
assert isinstance(stat, pd.DataFrame)
assert stat["up_count"].iloc[0] == 3000
assert stat["down_count"].iloc[0] == 2000
assert stat["neutral_count"].iloc[0] == 500
assert stat["total_count"].iloc[0] == 5500
def test_get_history_fund_flow_parsing():
"""测试历史资金流序列解析逻辑。"""
from easy_tdx.commands.fund_flow import GetHistoryFundFlowCmd
# 模拟 Category 22 响应 (Header 9 + Count 2 + Body 36)
body = bytearray(9)
body.extend(struct.pack("<H", 1)) # 1 record
# Record: Date(I) + 8 * custom_float(uint32)
# 2025-01-08
body.extend(struct.pack("<H", 1))
date = 20250108
# 模拟 8 个流向金额
record = struct.pack("<IIIIIIIII", date, 100, 200, 300, 400, 500, 600, 700, 800)
body.extend(record)
cmd = GetHistoryFundFlowCmd(Market.SH, "600000", 0, 1)
res = cmd.parse_response(bytes(body))
assert len(res) == 1
assert res[0].year == 2025
assert res[0].month == 1
@@ -139,6 +182,8 @@ def test_get_history_fund_flow_parsing():
@patch("easy_tdx.client.TdxConnection")
def test_get_history_fund_flow_fallback(_mock_conn_cls):
"""Category 22 空回包时,自动回退到历史逐笔重算。"""
from easy_tdx.commands.fund_flow import GetHistoryFundFlowCmd
client = TdxClient("127.0.0.1")
bars = [
@@ -155,46 +200,27 @@ def test_get_history_fund_flow_fallback(_mock_conn_cls):
],
}
def mock_history_txn(_market, _code, date, start, count):
if start > 0:
def mock_execute(cmd):
if isinstance(cmd, GetHistoryFundFlowCmd):
return []
return txn_map[date]
if isinstance(cmd, GetSecurityBarsCmd):
return bars
if isinstance(cmd, GetHistoryTransactionDataCmd):
if cmd.start > 0:
return []
return txn_map.get(cmd.date, [])
return []
with patch.object(TdxClient, "_execute", return_value=[]), patch.object(
TdxClient, "get_security_bars", return_value=bars
), patch.object(
TdxClient, "get_history_transaction_data", side_effect=mock_history_txn
):
with patch.object(TdxClient, "_execute", side_effect=mock_execute):
flows = client.get_history_fund_flow(Market.SH, "600000", 0, 2)
assert flows == [
HistoricalFundFlow(
year=2025,
month=1,
day=8,
super_in=1010000.0,
super_out=0.0,
large_in=0.0,
large_out=250000.0,
medium_in=0.0,
medium_out=0.0,
small_in=0.0,
small_out=0.0,
),
HistoricalFundFlow(
year=2025,
month=1,
day=9,
super_in=0.0,
super_out=0.0,
large_in=0.0,
large_out=0.0,
medium_in=0.0,
medium_out=0.0,
small_in=10000.0,
small_out=0.0,
),
]
assert isinstance(flows, pd.DataFrame)
assert len(flows) == 2
row0 = flows.iloc[0]
assert row0["super_in"] == 1010000.0
assert row0["large_out"] == 250000.0
row1 = flows.iloc[1]
assert row1["small_in"] == 10000.0
@patch("easy_tdx.client.TdxConnection")
@@ -202,21 +228,23 @@ def test_get_price_limits_uses_listing_window(_mock_conn_cls):
"""client.get_price_limits 应结合日 K 条数判断上市初期限价窗口。"""
client = TdxClient("127.0.0.1")
with patch.object(
TdxClient,
"get_security_bars",
return_value=[SecurityBar(0, 0, 0, 0, 0, 0, 2025, 1, 1, 15, 0)] * 5,
):
def mock_execute_5(cmd):
if isinstance(cmd, GetSecurityBarsCmd):
return [SecurityBar(0, 0, 0, 0, 0, 0, 2025, 1, 1, 15, 0)] * 5
return []
with patch.object(TdxClient, "_execute", side_effect=mock_execute_5):
assert client.get_price_limits(Market.SH, "600001", "主板新股", 10.0) == (
None,
None,
)
with patch.object(
TdxClient,
"get_security_bars",
return_value=[SecurityBar(0, 0, 0, 0, 0, 0, 2025, 1, 1, 15, 0)] * 6,
):
def mock_execute_6(cmd):
if isinstance(cmd, GetSecurityBarsCmd):
return [SecurityBar(0, 0, 0, 0, 0, 0, 2025, 1, 1, 15, 0)] * 6
return []
with patch.object(TdxClient, "_execute", side_effect=mock_execute_6):
assert client.get_price_limits(Market.SH, "600001", "主板老股", 10.0) == (
11.0,
9.0,
@@ -224,67 +252,50 @@ def test_get_price_limits_uses_listing_window(_mock_conn_cls):
@patch("easy_tdx.client.TdxConnection")
def test_get_minute_time_data_prefers_history_endpoint(_mock_conn_cls):
"""今日分时优先走历史分时接口,规避当前分时协议歧义"""
def test_get_minute_time_data_uses_history_endpoint(_mock_conn_cls):
"""今日分时走历史分时接口。"""
client = TdxClient("127.0.0.1")
expected = [MinuteBar(price=9.7, vol=13694)]
with patch("easy_tdx.client._today_in_shanghai", return_value=20260422), patch.object(
TdxClient,
"get_history_minute_time_data",
return_value=expected,
) as mock_history, patch.object(
TdxClient,
"_execute",
side_effect=AssertionError("should not hit current-minute command"),
def mock_execute(cmd):
if isinstance(cmd, GetHistoryMinuteTimeDataCmd):
return expected
return []
with (
patch("easy_tdx.client._today_in_shanghai", return_value=20260422),
patch.object(TdxClient, "_execute", side_effect=mock_execute) as mock_exec,
):
result = client.get_minute_time_data(Market.SH, "600000")
mock_history.assert_called_once_with(Market.SH, "600000", 20260422)
assert result == expected
assert isinstance(result, pd.DataFrame)
assert result["price"].iloc[0] == 9.7
history_calls = [
c for c in mock_exec.call_args_list if isinstance(c[0][0], GetHistoryMinuteTimeDataCmd)
]
assert len(history_calls) == 1
@patch("easy_tdx.client.TdxConnection")
def test_get_minute_time_data_falls_back_to_current_endpoint(_mock_conn_cls):
"""历史分时失败时,仍回退到原今日分时命令。"""
client = TdxClient("127.0.0.1")
fallback = [MinuteBar(price=9.61, vol=10698)]
with patch("easy_tdx.client._today_in_shanghai", return_value=20260422), patch.object(
TdxClient,
"get_history_minute_time_data",
side_effect=RuntimeError("history unavailable"),
) as mock_history, patch.object(
TdxClient,
"_execute",
return_value=fallback,
) as mock_execute:
result = client.get_minute_time_data(Market.SH, "600000")
mock_history.assert_called_once_with(Market.SH, "600000", 20260422)
mock_execute.assert_called_once()
assert result == fallback
def test_async_get_minute_time_data_prefers_history_endpoint():
"""异步客户端应与同步客户端保持同一回退策略。"""
def test_async_get_minute_time_data_uses_history_endpoint():
"""异步客户端走历史分时接口。"""
expected = [MinuteBar(price=9.7, vol=13694)]
async def run_test() -> None:
with patch("easy_tdx.client.AsyncTdxConnection"):
client = AsyncTdxClient("127.0.0.1")
with patch("easy_tdx.client._today_in_shanghai", return_value=20260422), patch.object(
AsyncTdxClient,
"get_history_minute_time_data",
return_value=expected,
) as mock_history, patch.object(
AsyncTdxClient,
"_execute",
side_effect=AssertionError("should not hit current-minute command"),
async def mock_execute(cmd):
if isinstance(cmd, GetHistoryMinuteTimeDataCmd):
return expected
return []
with (
patch("easy_tdx.client._today_in_shanghai", return_value=20260422),
patch.object(AsyncTdxClient, "_execute", side_effect=mock_execute),
):
result = await client.get_minute_time_data(Market.SH, "600000")
mock_history.assert_called_once_with(Market.SH, "600000", 20260422)
assert result == expected
assert isinstance(result, pd.DataFrame)
assert result["price"].iloc[0] == 9.7
asyncio.run(run_test())
+18 -14
View File
@@ -4,6 +4,8 @@ import asyncio
import struct
from unittest.mock import patch
import pandas as pd
from easy_tdx.client import AsyncTdxClient, TdxClient
from easy_tdx.codec.block import parse_block_dat
from easy_tdx.models.finance import TdxBlock
@@ -13,10 +15,11 @@ from easy_tdx.models.finance import TdxBlock
def test_async_get_block_info_logic(mock_conn_cls):
"""测试 AsyncTdxClient.get_block_info 的异步拉取逻辑。"""
mock_conn = mock_conn_cls.return_value
# 模拟异步 execute
async def mock_execute(cmd):
from easy_tdx.commands.block_info import GetBlockInfoCmd, GetBlockInfoMetaCmd
if isinstance(cmd, GetBlockInfoMetaCmd):
return 100, "hash"
if isinstance(cmd, GetBlockInfoCmd):
@@ -32,9 +35,9 @@ def test_async_get_block_info_logic(mock_conn_cls):
with patch("easy_tdx.client.parse_block_dat") as mock_parse:
mock_parse.return_value = []
res = await client.get_block_info("test.dat")
assert isinstance(res, list)
assert mock_conn.execute.call_count == 2 # 1 meta + 1 data
assert isinstance(res, pd.DataFrame)
assert mock_conn.execute.call_count == 2 # 1 meta + 1 data
asyncio.run(main())
@@ -49,20 +52,20 @@ def test_parse_block_dat_basic():
# Header 384 + Count 2 + Record 2813
data = bytearray(384)
data.extend(struct.pack("<H", 1)) # 1 block
# Block Record: 9s (name) + H (count) + H (type) + 2800s (codes)
name = "测试板块".encode("gbk")
record = bytearray((name + b"\x00" * 9)[:9])
record.extend(struct.pack("<HH", 2, 1)) # 2 stocks, type 1
# 2 stocks: 600000, 000001
codes = "600000\x00000001\x00".encode("ascii")
record.extend((codes + b"\x00" * 2800)[:2800])
data.extend(record)
blocks = parse_block_dat(bytes(data), "block_gn.dat")
assert len(blocks) == 1
b = blocks[0]
assert b.name == "测试板块"
@@ -75,12 +78,13 @@ def test_parse_block_dat_basic():
def test_get_block_info_logic(mock_conn_cls):
"""测试 TdxClient.get_block_info 的分片拉取逻辑。"""
mock_conn = mock_conn_cls.return_value
client = TdxClient("127.0.0.1")
# 模拟 GetBlockInfoMeta 响应:size=35000 (需要2次拉取)
def mock_execute(cmd):
from easy_tdx.commands.block_info import GetBlockInfoCmd, GetBlockInfoMetaCmd
if isinstance(cmd, GetBlockInfoMetaCmd):
return 35000, "dummy_hash"
if isinstance(cmd, GetBlockInfoCmd):
@@ -89,16 +93,16 @@ def test_get_block_info_logic(mock_conn_cls):
return None
mock_conn.execute.side_effect = mock_execute
# 我们主要测试循环是否正确
with patch("easy_tdx.client.parse_block_dat") as mock_parse:
mock_parse.return_value = [TdxBlock("Test", 1, 0, [])]
res = client.get_block_info("test.dat")
assert len(res) == 1
# 应该调用了 1 (meta) + 2 (data: 30000 + 5000) = 3 次 execute
assert mock_conn.execute.call_count == 3
# 验证最后一次拉取的参数
last_call_args = mock_conn.execute.call_args_list[-1][0][0]
assert last_call_args.start == 30000
+27 -17
View File
@@ -4,6 +4,7 @@ fixtures/ 目录下每个 .hex 文件是一次真实服务器响应的 body(
对应的 .json 文件记录关键预期值,供手工核对。
此测试文件直接断言解析结果,无需网络连接。
"""
from __future__ import annotations
import pathlib
@@ -20,6 +21,7 @@ def load_hex(name: str) -> bytes:
# security_count
# ---------------------------------------------------------------------------
def test_security_count_parse():
from easy_tdx.commands.security_count import GetSecurityCountCmd
from easy_tdx.models.enums import Market
@@ -38,6 +40,7 @@ def test_security_count_parse():
# security_list
# ---------------------------------------------------------------------------
def test_security_list_parse():
from easy_tdx.commands.security_list import GetSecurityListCmd
from easy_tdx.models.enums import Market
@@ -61,18 +64,15 @@ def test_security_list_pre_close_uses_tdx_float_for_a_share():
from easy_tdx.commands.security_list import GetSecurityListCmd
from easy_tdx.models.enums import Market
body = (
struct.pack("<H", 1)
+ struct.pack(
"<6sH8s4sBI4s",
b"600000",
100,
"\u6d66\u53d1\u94f6\u884c".encode("gbk"),
b"\x00\x00\x00\x00",
2,
0x411B851F,
b"\x00\x00\x00\x00",
)
body = struct.pack("<H", 1) + struct.pack(
"<6sH8s4sBI4s",
b"600000",
100,
"\u6d66\u53d1\u94f6\u884c".encode("gbk"),
b"\x00\x00\x00\x00",
2,
0x411B851F,
b"\x00\x00\x00\x00",
)
record = GetSecurityListCmd(Market.SH, 24000).parse_response(body)[0]
@@ -97,6 +97,7 @@ def test_security_list_gbk_no_crash():
# security_bars
# ---------------------------------------------------------------------------
def test_security_bars_parse():
from easy_tdx.commands.security_bars import GetSecurityBarsCmd
from easy_tdx.models.enums import KlineCategory, Market
@@ -128,6 +129,7 @@ def test_security_bars_parse():
# security_quotes
# ---------------------------------------------------------------------------
def test_security_quotes_parse():
from easy_tdx.commands.security_quotes import GetSecurityQuotesCmd
from easy_tdx.models.enums import Market
@@ -161,6 +163,7 @@ def test_security_quotes_parse():
# minute_time
# ---------------------------------------------------------------------------
def test_minute_time_parse():
from easy_tdx.commands.minute_time import GetMinuteTimeDataCmd
from easy_tdx.models.enums import Market
@@ -174,21 +177,22 @@ def test_minute_time_parse():
b0 = bars[0]
assert isinstance(b0.price, float)
assert isinstance(b0.vol, int)
# Bug #5 fix: unknown_1 is preserved, not discarded
assert hasattr(b0, "unknown_1")
assert isinstance(b0.unknown_1, int)
# Bug #5 fix: _unknown_1 is preserved, not discarded
assert hasattr(b0, "_unknown_1")
assert isinstance(b0._unknown_1, int)
assert len(b0._raw) > 0
# fixed values
assert abs(b0.price - 0.01) < 0.001
assert b0.vol == 48
assert b0.unknown_1 == 54
assert b0._unknown_1 == 54
# ---------------------------------------------------------------------------
# history_minute_time
# ---------------------------------------------------------------------------
def test_history_minute_time_parse():
from easy_tdx.commands.minute_time import GetHistoryMinuteTimeDataCmd
from easy_tdx.models.enums import Market
@@ -202,7 +206,7 @@ def test_history_minute_time_parse():
b0 = bars[0]
assert abs(b0.price - 10.29) < 0.01
assert b0.vol == 10044
assert hasattr(b0, "unknown_1")
assert hasattr(b0, "_unknown_1")
assert len(b0._raw) > 0
@@ -210,6 +214,7 @@ def test_history_minute_time_parse():
# transaction (current day)
# ---------------------------------------------------------------------------
def test_transaction_parse():
from easy_tdx.commands.transaction import GetTransactionDataCmd
from easy_tdx.models.enums import Market
@@ -239,6 +244,7 @@ def test_transaction_parse():
# history_transaction
# ---------------------------------------------------------------------------
def test_history_transaction_parse():
from easy_tdx.commands.transaction import GetHistoryTransactionDataCmd
from easy_tdx.models.enums import Market
@@ -266,6 +272,7 @@ def test_history_transaction_parse():
# xdxr_info
# ---------------------------------------------------------------------------
def test_xdxr_info_parse():
from easy_tdx.commands.xdxr_info import GetXdxrInfoCmd
from easy_tdx.models.enums import Market
@@ -329,6 +336,7 @@ def test_xdxr_info_category_1_normalizes_per_10_share_fields():
# finance_info
# ---------------------------------------------------------------------------
def test_finance_info_parse():
from easy_tdx.commands.finance_info import GetFinanceInfoCmd
from easy_tdx.models.enums import Market
@@ -354,6 +362,7 @@ def test_finance_info_parse():
# company_info_category
# ---------------------------------------------------------------------------
def test_company_info_category_parse():
from easy_tdx.commands.company_info import GetCompanyInfoCategoryCmd
from easy_tdx.models.enums import Market
@@ -375,6 +384,7 @@ def test_company_info_category_parse():
# company_info_content
# ---------------------------------------------------------------------------
def test_company_info_content_parse():
from easy_tdx.commands.company_info import GetCompanyInfoContentCmd
from easy_tdx.models.enums import Market