feat: add Nailong Fund advisor capabilities
This commit is contained in:
@@ -4,7 +4,7 @@ from decimal import Decimal
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
from app.infrastructure.fund_market_adapter import EastmoneyFundAdapter
|
||||
from app.infrastructure.fund_market_adapter import EastmoneyFundAdapter, HqFundMarketAdapter
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -43,3 +43,34 @@ async def test_adapter_retries_then_returns_degraded_history() -> None:
|
||||
assert result == {"degraded": True}
|
||||
assert calls == 2
|
||||
await client.aclose()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_hq_adapter_maps_snapshot_fields_without_network() -> None:
|
||||
calls = 0
|
||||
|
||||
def loader(*, target_date: str, fund_codes: list[str]) -> list[dict[str, object]]:
|
||||
nonlocal calls
|
||||
calls += 1
|
||||
assert fund_codes == ["159511"]
|
||||
return [{
|
||||
"基金代码": "159511",
|
||||
"基金名称": "南方测试基金",
|
||||
"基金净值": "1.23",
|
||||
"日期": target_date,
|
||||
"日涨幅": "0.82%",
|
||||
"最近半年": "8.10%",
|
||||
"最近一年": "12.30%",
|
||||
"今年以来": "4.50%",
|
||||
"成立以来": "30.00%",
|
||||
"是否盘中": True,
|
||||
}]
|
||||
|
||||
adapter = HqFundMarketAdapter(loader)
|
||||
target_date = date.today()
|
||||
assert await adapter.fetch_names(["159511"]) == {"159511": "南方测试基金"}
|
||||
assert (await adapter.fetch_quotes(["159511"]))["159511"]["nav"] == Decimal("1.23")
|
||||
history = await adapter.fetch_history("159511", target_date)
|
||||
assert history["half_year_return"] == Decimal("8.10")
|
||||
assert history["one_year_return"] == Decimal("12.30")
|
||||
assert calls == 1
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
import hq
|
||||
|
||||
|
||||
def test_hq_market_accepts_requested_fund_codes(monkeypatch) -> None:
|
||||
monkeypatch.setattr(hq, "_get_names", lambda codes: {code: f"基金-{code}" for code in codes})
|
||||
monkeypatch.setattr(
|
||||
hq,
|
||||
"_get_history",
|
||||
lambda codes, _target_date: {
|
||||
code: {
|
||||
"基金净值": "1.20",
|
||||
"日期": "2026-09-10",
|
||||
"日涨幅": "0.10%",
|
||||
"最近半年": "8.00%",
|
||||
"最近一年": "12.00%",
|
||||
"今年以来": "4.00%",
|
||||
"成立以来": "30.00%",
|
||||
}
|
||||
for code in codes
|
||||
},
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
hq,
|
||||
"_get_quotes",
|
||||
lambda codes: {code: {"基金净值": "1.23", "日涨幅": "0.20%"} for code in codes},
|
||||
)
|
||||
monkeypatch.setattr(hq, "is_market_trading_time", lambda: True)
|
||||
|
||||
result: list[dict[str, Any]] = hq.get_southern_fund_market(
|
||||
target_date="2026-09-10",
|
||||
fund_codes=["159511"],
|
||||
)
|
||||
|
||||
assert [row["基金代码"] for row in result] == ["159511"]
|
||||
assert result[0]["基金净值"] == "1.23"
|
||||
|
||||
|
||||
def test_hq_nav_history_filters_invalid_observations(monkeypatch) -> None:
|
||||
monkeypatch.setattr(
|
||||
hq,
|
||||
"_fetch_nav_records",
|
||||
lambda *_args, **_kwargs: [
|
||||
{"FSRQ": "2026-09-09", "DWJZ": "1.20"},
|
||||
{"FSRQ": "2026-09-08", "DWJZ": "0"},
|
||||
{"FSRQ": "2026-08-01", "DWJZ": "1.10"},
|
||||
],
|
||||
)
|
||||
|
||||
result = hq.get_southern_fund_nav_history("159511", "2026-09-01", "2026-09-10")
|
||||
|
||||
assert result == [{"fund_code": "159511", "trade_date": "2026-09-09", "nav": "1.20"}]
|
||||
|
||||
|
||||
def test_hq_history_paginates_a_bounded_date_range_without_total_count(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
pages = {
|
||||
1: [{"FSRQ": "2026-09-03", "DWJZ": "1.03"}, {"FSRQ": "2026-09-02", "DWJZ": "1.02"}],
|
||||
2: [{"FSRQ": "2026-09-01", "DWJZ": "1.01"}, {"FSRQ": "2026-08-29", "DWJZ": "1.00"}],
|
||||
3: [],
|
||||
}
|
||||
monkeypatch.setattr(
|
||||
hq,
|
||||
"_fetch_nav_page",
|
||||
lambda _code, page, _start, _end: (pages[page], None),
|
||||
)
|
||||
|
||||
result = hq._fetch_nav_records("159511", "2026-08-01", "2026-09-10", all_pages=True)
|
||||
|
||||
assert [row["FSRQ"] for row in result] == [
|
||||
"2026-09-03", "2026-09-02", "2026-09-01", "2026-08-29"
|
||||
]
|
||||
|
||||
|
||||
def test_tencent_exchange_quote_parser_keeps_only_compatible_fields() -> None:
|
||||
fields = [""] * 34
|
||||
fields[3] = "1.234"
|
||||
fields[4] = "1.200"
|
||||
fields[6] = "1000"
|
||||
fields[33] = "2.83"
|
||||
payload = f'v_sz159511="{"~".join(fields)}";'.encode("gbk")
|
||||
|
||||
quotes = hq._parse_tencent_exchange_quotes(payload, ("159511",))
|
||||
|
||||
assert quotes == {
|
||||
"159511": {
|
||||
"last_price": "1.234",
|
||||
"previous_close": "1.200",
|
||||
"change_pct": "2.83",
|
||||
"volume": "1000",
|
||||
"turnover_amount": None,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user