mirror of
https://ghfast.top/https://github.com/aeroxw/easy-tdx.git
synced 2026-09-12 15:44:15 +08:00
feat!: rename project from xmtdx to easy-tdx
- Package directory: src/xmtdx/ -> src/easy_tdx/ - Import path: from easy_tdx import ... - pip install easy-tdx - Add LICENSE (MIT) with upstream attribution (pytdx, xmtdx) - Add NOTICE with detailed attribution - Update all examples, tests, scripts, docs - Bump version to 1.0.0 BREAKING CHANGE: import path changed from `xmtdx` to `easy_tdx` Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
9c5672b4d2
commit
50491f9aae
@@ -10,7 +10,7 @@ import os
|
||||
|
||||
import pytest
|
||||
|
||||
from xmtdx import AsyncTdxClient, Market, TdxClient
|
||||
from easy_tdx import AsyncTdxClient, Market, TdxClient
|
||||
|
||||
_LIVE_ENABLED = os.getenv("XMTDX_LIVE") == "1"
|
||||
_LIVE_HOST = os.getenv("XMTDX_HOST", "180.153.18.170")
|
||||
|
||||
@@ -4,17 +4,17 @@ import asyncio
|
||||
import struct
|
||||
from unittest.mock import patch
|
||||
|
||||
from xmtdx import AsyncTdxClient, Market, TdxClient
|
||||
from xmtdx.client import _classify_fund_flow
|
||||
from xmtdx.models.bar import SecurityBar
|
||||
from xmtdx.models.quote import SecurityQuote
|
||||
from xmtdx.models.security import SecurityInfo
|
||||
from xmtdx.models.stats import HistoricalFundFlow
|
||||
from xmtdx.models.timeseries import MinuteBar
|
||||
from xmtdx.models.timeseries import TransactionRecord
|
||||
from easy_tdx import AsyncTdxClient, Market, TdxClient
|
||||
from easy_tdx.client import _classify_fund_flow
|
||||
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
|
||||
|
||||
|
||||
@patch("xmtdx.client.TdxConnection")
|
||||
@patch("easy_tdx.client.TdxConnection")
|
||||
def test_get_fund_flow_logic(_mock_conn_cls):
|
||||
"""测试资金流分类计算逻辑。"""
|
||||
client = TdxClient("127.0.0.1")
|
||||
@@ -48,7 +48,7 @@ def test_classify_fund_flow_exact_thresholds_use_lower_bucket():
|
||||
assert flow.medium_in == 200000.0
|
||||
assert flow.small_in == 40000.0
|
||||
|
||||
@patch("xmtdx.client.TdxConnection")
|
||||
@patch("easy_tdx.client.TdxConnection")
|
||||
def test_get_security_list_all_filtering(_mock_conn_cls):
|
||||
"""测试三市 A 股过滤与行业挂载逻辑。"""
|
||||
client = TdxClient("127.0.0.1")
|
||||
@@ -84,7 +84,7 @@ def test_get_security_list_all_filtering(_mock_conn_cls):
|
||||
s0 = next(s for s in all_stocks if s.code == "600000")
|
||||
assert s0.industry_tdx == "T01"
|
||||
|
||||
@patch("xmtdx.client.TdxConnection")
|
||||
@patch("easy_tdx.client.TdxConnection")
|
||||
def test_get_market_stat_mapping(_mock_conn_cls):
|
||||
"""测试市场统计字段映射。"""
|
||||
client = TdxClient("127.0.0.1")
|
||||
@@ -114,7 +114,7 @@ def test_get_market_stat_mapping(_mock_conn_cls):
|
||||
|
||||
def test_get_history_fund_flow_parsing():
|
||||
"""测试历史资金流序列解析逻辑。"""
|
||||
from xmtdx.commands.fund_flow import GetHistoryFundFlowCmd
|
||||
from easy_tdx.commands.fund_flow import GetHistoryFundFlowCmd
|
||||
|
||||
# 模拟 Category 22 响应 (Header 9 + Count 2 + Body 36)
|
||||
body = bytearray(9)
|
||||
@@ -136,7 +136,7 @@ def test_get_history_fund_flow_parsing():
|
||||
assert res[0].day == 8
|
||||
|
||||
|
||||
@patch("xmtdx.client.TdxConnection")
|
||||
@patch("easy_tdx.client.TdxConnection")
|
||||
def test_get_history_fund_flow_fallback(_mock_conn_cls):
|
||||
"""Category 22 空回包时,自动回退到历史逐笔重算。"""
|
||||
client = TdxClient("127.0.0.1")
|
||||
@@ -197,7 +197,7 @@ def test_get_history_fund_flow_fallback(_mock_conn_cls):
|
||||
]
|
||||
|
||||
|
||||
@patch("xmtdx.client.TdxConnection")
|
||||
@patch("easy_tdx.client.TdxConnection")
|
||||
def test_get_price_limits_uses_listing_window(_mock_conn_cls):
|
||||
"""client.get_price_limits 应结合日 K 条数判断上市初期限价窗口。"""
|
||||
client = TdxClient("127.0.0.1")
|
||||
@@ -223,13 +223,13 @@ def test_get_price_limits_uses_listing_window(_mock_conn_cls):
|
||||
)
|
||||
|
||||
|
||||
@patch("xmtdx.client.TdxConnection")
|
||||
@patch("easy_tdx.client.TdxConnection")
|
||||
def test_get_minute_time_data_prefers_history_endpoint(_mock_conn_cls):
|
||||
"""今日分时优先走历史分时接口,规避当前分时协议歧义。"""
|
||||
client = TdxClient("127.0.0.1")
|
||||
expected = [MinuteBar(price=9.7, vol=13694)]
|
||||
|
||||
with patch("xmtdx.client._today_in_shanghai", return_value=20260422), patch.object(
|
||||
with patch("easy_tdx.client._today_in_shanghai", return_value=20260422), patch.object(
|
||||
TdxClient,
|
||||
"get_history_minute_time_data",
|
||||
return_value=expected,
|
||||
@@ -244,13 +244,13 @@ def test_get_minute_time_data_prefers_history_endpoint(_mock_conn_cls):
|
||||
assert result == expected
|
||||
|
||||
|
||||
@patch("xmtdx.client.TdxConnection")
|
||||
@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("xmtdx.client._today_in_shanghai", return_value=20260422), patch.object(
|
||||
with patch("easy_tdx.client._today_in_shanghai", return_value=20260422), patch.object(
|
||||
TdxClient,
|
||||
"get_history_minute_time_data",
|
||||
side_effect=RuntimeError("history unavailable"),
|
||||
@@ -271,9 +271,9 @@ def test_async_get_minute_time_data_prefers_history_endpoint():
|
||||
expected = [MinuteBar(price=9.7, vol=13694)]
|
||||
|
||||
async def run_test() -> None:
|
||||
with patch("xmtdx.client.AsyncTdxConnection"):
|
||||
with patch("easy_tdx.client.AsyncTdxConnection"):
|
||||
client = AsyncTdxClient("127.0.0.1")
|
||||
with patch("xmtdx.client._today_in_shanghai", return_value=20260422), patch.object(
|
||||
with patch("easy_tdx.client._today_in_shanghai", return_value=20260422), patch.object(
|
||||
AsyncTdxClient,
|
||||
"get_history_minute_time_data",
|
||||
return_value=expected,
|
||||
|
||||
@@ -6,10 +6,10 @@ import asyncio
|
||||
import struct
|
||||
import time
|
||||
|
||||
from xmtdx import AsyncTdxClient, Market
|
||||
from xmtdx.commands.security_count import GetSecurityCountCmd
|
||||
from xmtdx.commands.setup import SETUP_COMMANDS
|
||||
from xmtdx.exceptions import TdxConnectionError
|
||||
from easy_tdx import AsyncTdxClient, Market
|
||||
from easy_tdx.commands.security_count import GetSecurityCountCmd
|
||||
from easy_tdx.commands.setup import SETUP_COMMANDS
|
||||
from easy_tdx.exceptions import TdxConnectionError
|
||||
|
||||
|
||||
def _pack_frame(body: bytes) -> bytes:
|
||||
|
||||
@@ -4,19 +4,19 @@ import asyncio
|
||||
import struct
|
||||
from unittest.mock import patch
|
||||
|
||||
from xmtdx.client import AsyncTdxClient, TdxClient
|
||||
from xmtdx.codec.block import parse_block_dat
|
||||
from xmtdx.models.finance import TdxBlock
|
||||
from easy_tdx.client import AsyncTdxClient, TdxClient
|
||||
from easy_tdx.codec.block import parse_block_dat
|
||||
from easy_tdx.models.finance import TdxBlock
|
||||
|
||||
|
||||
@patch("xmtdx.client.AsyncTdxConnection")
|
||||
@patch("easy_tdx.client.AsyncTdxConnection")
|
||||
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 xmtdx.commands.block_info import GetBlockInfoCmd, GetBlockInfoMetaCmd
|
||||
from easy_tdx.commands.block_info import GetBlockInfoCmd, GetBlockInfoMetaCmd
|
||||
if isinstance(cmd, GetBlockInfoMetaCmd):
|
||||
return 100, "hash"
|
||||
if isinstance(cmd, GetBlockInfoCmd):
|
||||
@@ -29,7 +29,7 @@ def test_async_get_block_info_logic(mock_conn_cls):
|
||||
|
||||
async def main():
|
||||
client = AsyncTdxClient("127.0.0.1")
|
||||
with patch("xmtdx.client.parse_block_dat") as mock_parse:
|
||||
with patch("easy_tdx.client.parse_block_dat") as mock_parse:
|
||||
mock_parse.return_value = []
|
||||
res = await client.get_block_info("test.dat")
|
||||
|
||||
@@ -71,7 +71,7 @@ def test_parse_block_dat_basic():
|
||||
assert b.codes == ["600000", "000001"]
|
||||
|
||||
|
||||
@patch("xmtdx.client.TdxConnection")
|
||||
@patch("easy_tdx.client.TdxConnection")
|
||||
def test_get_block_info_logic(mock_conn_cls):
|
||||
"""测试 TdxClient.get_block_info 的分片拉取逻辑。"""
|
||||
mock_conn = mock_conn_cls.return_value
|
||||
@@ -80,7 +80,7 @@ def test_get_block_info_logic(mock_conn_cls):
|
||||
|
||||
# 模拟 GetBlockInfoMeta 响应:size=35000 (需要2次拉取)
|
||||
def mock_execute(cmd):
|
||||
from xmtdx.commands.block_info import GetBlockInfoCmd, GetBlockInfoMetaCmd
|
||||
from easy_tdx.commands.block_info import GetBlockInfoCmd, GetBlockInfoMetaCmd
|
||||
if isinstance(cmd, GetBlockInfoMetaCmd):
|
||||
return 35000, "dummy_hash"
|
||||
if isinstance(cmd, GetBlockInfoCmd):
|
||||
@@ -91,7 +91,7 @@ def test_get_block_info_logic(mock_conn_cls):
|
||||
mock_conn.execute.side_effect = mock_execute
|
||||
|
||||
# 我们主要测试循环是否正确
|
||||
with patch("xmtdx.client.parse_block_dat") as mock_parse:
|
||||
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")
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import struct
|
||||
|
||||
from xmtdx.codec.datetime_ import get_datetime, get_datetime_day, get_datetime_minute, get_time
|
||||
from easy_tdx.codec.datetime_ import get_datetime, get_datetime_day, get_datetime_minute, get_time
|
||||
|
||||
|
||||
def _pack_minute(year: int, month: int, day: int, hour: int, minute: int) -> bytes:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import struct
|
||||
import zlib
|
||||
|
||||
from xmtdx.codec.frame import HEADER_SIZE, decompress_body, parse_header
|
||||
from easy_tdx.codec.frame import HEADER_SIZE, decompress_body, parse_header
|
||||
|
||||
|
||||
def _make_header(zipsize: int, unzipsize: int) -> bytes:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""get_price / put_price 单元测试,测试向量来自 pytdx 实际报文。"""
|
||||
|
||||
from xmtdx.codec.price import get_price, put_price
|
||||
from easy_tdx.codec.price import get_price, put_price
|
||||
|
||||
|
||||
class TestGetPrice:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import struct
|
||||
|
||||
from xmtdx.codec.volume import get_volume
|
||||
from easy_tdx.codec.volume import get_volume
|
||||
|
||||
|
||||
def _pack(ivol: int) -> bytes:
|
||||
@@ -18,7 +18,7 @@ class TestGetVolume:
|
||||
def test_known_value_4098(self):
|
||||
# pytdx 注释 "4098 ---> 3.0" 含义:raw 4098 对应真实股数 3.0亿,
|
||||
# 但 get_volume(4098) ≈ 5.88e-39(接近零),说明 xdxr_info 里对股本字段
|
||||
# 调用 get_volume 是错误用法。xmtdx 在 xdxr_info 命令中会用正确的解码方式。
|
||||
# 调用 get_volume 是错误用法。easy-tdx 在 xdxr_info 命令中会用正确的解码方式。
|
||||
val, pos = get_volume(_pack(4098), 0)
|
||||
assert abs(val) < 1e-30 # 接近零,与 pytdx 行为一致
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ def load_hex(name: str) -> bytes:
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_security_count_parse():
|
||||
from xmtdx.commands.security_count import GetSecurityCountCmd
|
||||
from xmtdx.models.enums import Market
|
||||
from easy_tdx.commands.security_count import GetSecurityCountCmd
|
||||
from easy_tdx.models.enums import Market
|
||||
|
||||
body = load_hex("security_count")
|
||||
cmd = GetSecurityCountCmd(Market.SH)
|
||||
@@ -39,8 +39,8 @@ def test_security_count_parse():
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_security_list_parse():
|
||||
from xmtdx.commands.security_list import GetSecurityListCmd
|
||||
from xmtdx.models.enums import Market
|
||||
from easy_tdx.commands.security_list import GetSecurityListCmd
|
||||
from easy_tdx.models.enums import Market
|
||||
|
||||
body = load_hex("security_list")
|
||||
cmd = GetSecurityListCmd(Market.SH, 0)
|
||||
@@ -58,8 +58,8 @@ def test_security_list_parse():
|
||||
|
||||
|
||||
def test_security_list_pre_close_uses_tdx_float_for_a_share():
|
||||
from xmtdx.commands.security_list import GetSecurityListCmd
|
||||
from xmtdx.models.enums import Market
|
||||
from easy_tdx.commands.security_list import GetSecurityListCmd
|
||||
from easy_tdx.models.enums import Market
|
||||
|
||||
body = (
|
||||
struct.pack("<H", 1)
|
||||
@@ -84,8 +84,8 @@ def test_security_list_pre_close_uses_tdx_float_for_a_share():
|
||||
|
||||
def test_security_list_gbk_no_crash():
|
||||
"""Bug #2 修复验证:GBK 解码不崩溃,所有记录均有 code。"""
|
||||
from xmtdx.commands.security_list import GetSecurityListCmd
|
||||
from xmtdx.models.enums import Market
|
||||
from easy_tdx.commands.security_list import GetSecurityListCmd
|
||||
from easy_tdx.models.enums import Market
|
||||
|
||||
body = load_hex("security_list")
|
||||
cmd = GetSecurityListCmd(Market.SH, 0)
|
||||
@@ -98,8 +98,8 @@ def test_security_list_gbk_no_crash():
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_security_bars_parse():
|
||||
from xmtdx.commands.security_bars import GetSecurityBarsCmd
|
||||
from xmtdx.models.enums import KlineCategory, Market
|
||||
from easy_tdx.commands.security_bars import GetSecurityBarsCmd
|
||||
from easy_tdx.models.enums import KlineCategory, Market
|
||||
|
||||
body = load_hex("security_bars")
|
||||
cmd = GetSecurityBarsCmd(Market.SH, "600000", KlineCategory.DAY, 0, 5)
|
||||
@@ -129,8 +129,8 @@ def test_security_bars_parse():
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_security_quotes_parse():
|
||||
from xmtdx.commands.security_quotes import GetSecurityQuotesCmd
|
||||
from xmtdx.models.enums import Market
|
||||
from easy_tdx.commands.security_quotes import GetSecurityQuotesCmd
|
||||
from easy_tdx.models.enums import Market
|
||||
|
||||
body = load_hex("security_quotes")
|
||||
cmd = GetSecurityQuotesCmd([(Market.SH, "600000")])
|
||||
@@ -162,8 +162,8 @@ def test_security_quotes_parse():
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_minute_time_parse():
|
||||
from xmtdx.commands.minute_time import GetMinuteTimeDataCmd
|
||||
from xmtdx.models.enums import Market
|
||||
from easy_tdx.commands.minute_time import GetMinuteTimeDataCmd
|
||||
from easy_tdx.models.enums import Market
|
||||
|
||||
body = load_hex("minute_time")
|
||||
cmd = GetMinuteTimeDataCmd(Market.SH, "600000")
|
||||
@@ -190,8 +190,8 @@ def test_minute_time_parse():
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_history_minute_time_parse():
|
||||
from xmtdx.commands.minute_time import GetHistoryMinuteTimeDataCmd
|
||||
from xmtdx.models.enums import Market
|
||||
from easy_tdx.commands.minute_time import GetHistoryMinuteTimeDataCmd
|
||||
from easy_tdx.models.enums import Market
|
||||
|
||||
body = load_hex("history_minute_time")
|
||||
cmd = GetHistoryMinuteTimeDataCmd(Market.SH, "600000", 20250108)
|
||||
@@ -211,8 +211,8 @@ def test_history_minute_time_parse():
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_transaction_parse():
|
||||
from xmtdx.commands.transaction import GetTransactionDataCmd
|
||||
from xmtdx.models.enums import Market
|
||||
from easy_tdx.commands.transaction import GetTransactionDataCmd
|
||||
from easy_tdx.models.enums import Market
|
||||
|
||||
body = load_hex("transaction")
|
||||
cmd = GetTransactionDataCmd(Market.SH, "600000", 0, 10)
|
||||
@@ -240,8 +240,8 @@ def test_transaction_parse():
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_history_transaction_parse():
|
||||
from xmtdx.commands.transaction import GetHistoryTransactionDataCmd
|
||||
from xmtdx.models.enums import Market
|
||||
from easy_tdx.commands.transaction import GetHistoryTransactionDataCmd
|
||||
from easy_tdx.models.enums import Market
|
||||
|
||||
body = load_hex("history_transaction")
|
||||
cmd = GetHistoryTransactionDataCmd(Market.SH, "600000", 20250108, 0, 10)
|
||||
@@ -267,8 +267,8 @@ def test_history_transaction_parse():
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_xdxr_info_parse():
|
||||
from xmtdx.commands.xdxr_info import GetXdxrInfoCmd
|
||||
from xmtdx.models.enums import Market
|
||||
from easy_tdx.commands.xdxr_info import GetXdxrInfoCmd
|
||||
from easy_tdx.models.enums import Market
|
||||
|
||||
body = load_hex("xdxr_info")
|
||||
cmd = GetXdxrInfoCmd(Market.SH, "600000")
|
||||
@@ -306,8 +306,8 @@ def test_xdxr_info_parse():
|
||||
|
||||
|
||||
def test_xdxr_info_category_1_normalizes_per_10_share_fields():
|
||||
from xmtdx.commands.xdxr_info import GetXdxrInfoCmd
|
||||
from xmtdx.models.enums import Market
|
||||
from easy_tdx.commands.xdxr_info import GetXdxrInfoCmd
|
||||
from easy_tdx.models.enums import Market
|
||||
|
||||
body = bytearray(b"\x00" * 9)
|
||||
body.extend(struct.pack("<H", 1))
|
||||
@@ -330,8 +330,8 @@ def test_xdxr_info_category_1_normalizes_per_10_share_fields():
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_finance_info_parse():
|
||||
from xmtdx.commands.finance_info import GetFinanceInfoCmd
|
||||
from xmtdx.models.enums import Market
|
||||
from easy_tdx.commands.finance_info import GetFinanceInfoCmd
|
||||
from easy_tdx.models.enums import Market
|
||||
|
||||
body = load_hex("finance_info")
|
||||
cmd = GetFinanceInfoCmd(Market.SH, "600000")
|
||||
@@ -355,8 +355,8 @@ def test_finance_info_parse():
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_company_info_category_parse():
|
||||
from xmtdx.commands.company_info import GetCompanyInfoCategoryCmd
|
||||
from xmtdx.models.enums import Market
|
||||
from easy_tdx.commands.company_info import GetCompanyInfoCategoryCmd
|
||||
from easy_tdx.models.enums import Market
|
||||
|
||||
body = load_hex("company_info_category")
|
||||
cmd = GetCompanyInfoCategoryCmd(Market.SH, "600000")
|
||||
@@ -376,8 +376,8 @@ def test_company_info_category_parse():
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_company_info_content_parse():
|
||||
from xmtdx.commands.company_info import GetCompanyInfoContentCmd
|
||||
from xmtdx.models.enums import Market
|
||||
from easy_tdx.commands.company_info import GetCompanyInfoContentCmd
|
||||
from easy_tdx.models.enums import Market
|
||||
|
||||
body = load_hex("company_info_content")
|
||||
cmd = GetCompanyInfoContentCmd(Market.SH, "600000", "600000.txt", 0, 11426)
|
||||
|
||||
@@ -6,12 +6,12 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from xmtdx.codec.frame import FrameHeader, decompress_body
|
||||
from xmtdx.commands.company_info import GetCompanyInfoCategoryCmd
|
||||
from xmtdx.commands.security_count import GetSecurityCountCmd
|
||||
from xmtdx.commands.xdxr_info import GetXdxrInfoCmd
|
||||
from xmtdx.exceptions import TdxDecodeError
|
||||
from xmtdx.models.enums import Market
|
||||
from easy_tdx.codec.frame import FrameHeader, decompress_body
|
||||
from easy_tdx.commands.company_info import GetCompanyInfoCategoryCmd
|
||||
from easy_tdx.commands.security_count import GetSecurityCountCmd
|
||||
from easy_tdx.commands.xdxr_info import GetXdxrInfoCmd
|
||||
from easy_tdx.exceptions import TdxDecodeError
|
||||
from easy_tdx.models.enums import Market
|
||||
|
||||
FIXTURES = Path(__file__).parent.parent / "fixtures"
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
import struct
|
||||
|
||||
from xmtdx.codec.financial import parse_financial_dat, parse_financial_file_list
|
||||
from xmtdx.models.finance import FinancialFileInfo, FinancialRecord
|
||||
from easy_tdx.codec.financial import parse_financial_dat, parse_financial_file_list
|
||||
from easy_tdx.models.finance import FinancialFileInfo, FinancialRecord
|
||||
|
||||
|
||||
class TestParseFinancialFileList:
|
||||
@@ -109,7 +109,7 @@ class TestFinancialModels:
|
||||
assert fi.filesize == 100
|
||||
|
||||
def test_record(self) -> None:
|
||||
from xmtdx.models.enums import Market
|
||||
from easy_tdx.models.enums import Market
|
||||
|
||||
r = FinancialRecord(
|
||||
code="600519", market=Market.SH, report_date=20260331, fields=[1.0, 2.0]
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
import asyncio
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from xmtdx import AsyncTdxClient
|
||||
from easy_tdx import AsyncTdxClient
|
||||
|
||||
|
||||
def test_heartbeat_sends_periodically():
|
||||
async def run_test():
|
||||
# 模拟连接和执行
|
||||
with patch("xmtdx.client.AsyncTdxConnection") as mock_conn_cls:
|
||||
with patch("easy_tdx.client.AsyncTdxConnection") as mock_conn_cls:
|
||||
mock_conn = mock_conn_cls.return_value
|
||||
mock_conn.connect = AsyncMock()
|
||||
mock_conn.close = AsyncMock()
|
||||
@@ -40,7 +40,7 @@ def test_heartbeat_sends_periodically():
|
||||
|
||||
def test_heartbeat_stops_on_close():
|
||||
async def run_test():
|
||||
with patch("xmtdx.client.AsyncTdxConnection") as mock_conn_cls:
|
||||
with patch("easy_tdx.client.AsyncTdxConnection") as mock_conn_cls:
|
||||
mock_conn = mock_conn_cls.return_value
|
||||
mock_conn.connect = AsyncMock()
|
||||
mock_conn.close = AsyncMock()
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
import struct
|
||||
from unittest.mock import patch
|
||||
|
||||
from xmtdx.codec.price_rules import compute_price_limits
|
||||
from xmtdx.commands.fund_flow import GetHistoryFundFlowCmd
|
||||
from xmtdx.commands.security_bars import GetSecurityBarsCmd
|
||||
from xmtdx.commands.security_list import GetSecurityListCmd
|
||||
from xmtdx.commands.security_quotes import GetSecurityQuotesCmd
|
||||
from xmtdx.models.enums import KlineCategory, Market
|
||||
from easy_tdx.codec.price_rules import compute_price_limits
|
||||
from easy_tdx.commands.fund_flow import GetHistoryFundFlowCmd
|
||||
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.models.enums import KlineCategory, Market
|
||||
|
||||
|
||||
def test_security_bars_exact_layout():
|
||||
@@ -53,7 +53,7 @@ def test_security_list_request_length():
|
||||
|
||||
def test_security_quotes_limit_mapping():
|
||||
"""验证涨跌停价现在返回 None,且 pre_close 正确。"""
|
||||
from xmtdx.codec.price import put_price
|
||||
from easy_tdx.codec.price import put_price
|
||||
|
||||
cmd = GetSecurityQuotesCmd([(Market.SH, "600000")])
|
||||
|
||||
@@ -96,7 +96,7 @@ def test_security_quotes_limit_mapping():
|
||||
|
||||
def test_security_quotes_server_time_format():
|
||||
"""服务器时间应按“小时 + 百万分之一小时”统一解码。"""
|
||||
from xmtdx.commands.security_quotes import _format_server_time
|
||||
from easy_tdx.commands.security_quotes import _format_server_time
|
||||
|
||||
assert _format_server_time(9500000) == "09:30:00.000"
|
||||
assert _format_server_time(14999212) == "14:59:57.163"
|
||||
@@ -156,7 +156,7 @@ def test_history_fund_flow_uses_uint32_volume_words():
|
||||
seen.append(raw)
|
||||
return float(raw)
|
||||
|
||||
with patch("xmtdx.commands.fund_flow._decode_volume", side_effect=fake_decode):
|
||||
with patch("easy_tdx.commands.fund_flow._decode_volume", side_effect=fake_decode):
|
||||
records = GetHistoryFundFlowCmd(Market.SH, "600000", 0, 1).parse_response(bytes(body))
|
||||
|
||||
assert seen == raw_words
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from xmtdx.exceptions import TdxConnectionError
|
||||
from xmtdx.transport.sync import TdxConnection
|
||||
from easy_tdx.exceptions import TdxConnectionError
|
||||
from easy_tdx.transport.sync import TdxConnection
|
||||
|
||||
|
||||
class _FakeSocket:
|
||||
@@ -26,7 +26,7 @@ def test_sync_connection_closes_socket_when_setup_fails() -> None:
|
||||
sock = _FakeSocket()
|
||||
conn = TdxConnection("127.0.0.1", port=7709, timeout=0.2)
|
||||
|
||||
with patch("xmtdx.transport.sync.socket.socket", return_value=sock), patch.object(
|
||||
with patch("easy_tdx.transport.sync.socket.socket", return_value=sock), patch.object(
|
||||
TdxConnection,
|
||||
"_send_setup",
|
||||
side_effect=TdxConnectionError("setup failed"),
|
||||
|
||||
Reference in New Issue
Block a user