lib-x17-fintech 2.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lib_x17_fintech-2.1.3.dist-info/METADATA +633 -0
- lib_x17_fintech-2.1.3.dist-info/RECORD +282 -0
- lib_x17_fintech-2.1.3.dist-info/WHEEL +5 -0
- lib_x17_fintech-2.1.3.dist-info/licenses/LICENSE +1 -0
- lib_x17_fintech-2.1.3.dist-info/top_level.txt +1 -0
- xfintech/__init__.py +0 -0
- xfintech/connect/__init__.py +18 -0
- xfintech/connect/artifact/__init__.py +5 -0
- xfintech/connect/artifact/artifact.py +168 -0
- xfintech/connect/artifact/tests/__init__.py +3 -0
- xfintech/connect/artifact/tests/test_class_artifact_all.py +564 -0
- xfintech/connect/common/__init__.py +12 -0
- xfintech/connect/common/connect.py +49 -0
- xfintech/connect/common/connectref.py +119 -0
- xfintech/connect/common/error.py +62 -0
- xfintech/connect/common/tests/__init__.py +1 -0
- xfintech/connect/common/tests/test_class_connectlike_all.py +544 -0
- xfintech/connect/common/tests/test_class_connectref_all.py +586 -0
- xfintech/connect/common/tests/test_class_errors_all.py +524 -0
- xfintech/connect/instance/__init__.py +7 -0
- xfintech/connect/instance/macos.py +121 -0
- xfintech/connect/instance/s3.py +176 -0
- xfintech/connect/instance/tests/__init__.py +1 -0
- xfintech/connect/instance/tests/test_class_macosconnect_all.py +692 -0
- xfintech/connect/instance/tests/test_class_s3connect_all.py +603 -0
- xfintech/data/__init__.py +20 -0
- xfintech/data/common/__init__.py +15 -0
- xfintech/data/common/cache.py +186 -0
- xfintech/data/common/coolant.py +171 -0
- xfintech/data/common/metric.py +138 -0
- xfintech/data/common/paginate.py +132 -0
- xfintech/data/common/params.py +162 -0
- xfintech/data/common/retry.py +201 -0
- xfintech/data/common/tests/__init__.py +1 -0
- xfintech/data/common/tests/test_class_cache_all.py +681 -0
- xfintech/data/common/tests/test_class_coolant_all.py +534 -0
- xfintech/data/common/tests/test_class_metric_all.py +705 -0
- xfintech/data/common/tests/test_class_paginate_all.py +508 -0
- xfintech/data/common/tests/test_class_params_all.py +891 -0
- xfintech/data/common/tests/test_class_retry_all.py +714 -0
- xfintech/data/job/__init__.py +17 -0
- xfintech/data/job/errors.py +112 -0
- xfintech/data/job/house.py +156 -0
- xfintech/data/job/job.py +247 -0
- xfintech/data/job/joblike.py +47 -0
- xfintech/data/job/tests/__init__.py +1 -0
- xfintech/data/job/tests/test_class_errors_all.py +275 -0
- xfintech/data/job/tests/test_class_house_all.py +801 -0
- xfintech/data/job/tests/test_class_job_all.py +684 -0
- xfintech/data/job/tests/test_class_joblike_all.py +482 -0
- xfintech/data/relay/__init__.py +7 -0
- xfintech/data/relay/client.py +114 -0
- xfintech/data/relay/clientlike.py +45 -0
- xfintech/data/relay/tests/test_class_relayclient_all.py +484 -0
- xfintech/data/relay/tests/test_class_relayclientlike_all.py +500 -0
- xfintech/data/source/__init__.py +7 -0
- xfintech/data/source/baostock/__init__.py +21 -0
- xfintech/data/source/baostock/job/__init__.py +5 -0
- xfintech/data/source/baostock/job/job.py +217 -0
- xfintech/data/source/baostock/job/tests/__init__.py +0 -0
- xfintech/data/source/baostock/job/tests/test_class_baostockjob_all.py +547 -0
- xfintech/data/source/baostock/session/__init__.py +8 -0
- xfintech/data/source/baostock/session/relay.py +223 -0
- xfintech/data/source/baostock/session/session.py +241 -0
- xfintech/data/source/baostock/session/tests/__init__.py +0 -0
- xfintech/data/source/baostock/session/tests/test_class_relay_all.py +694 -0
- xfintech/data/source/baostock/session/tests/test_class_session_all.py +505 -0
- xfintech/data/source/baostock/stock/__init__.py +0 -0
- xfintech/data/source/baostock/stock/hs300stock/__init__.py +3 -0
- xfintech/data/source/baostock/stock/hs300stock/constant.py +49 -0
- xfintech/data/source/baostock/stock/hs300stock/hs300stock.py +133 -0
- xfintech/data/source/baostock/stock/hs300stock/tests/__init__.py +1 -0
- xfintech/data/source/baostock/stock/hs300stock/tests/test_class_hs300index_all.py +413 -0
- xfintech/data/source/baostock/stock/minuteline/__init__.py +19 -0
- xfintech/data/source/baostock/stock/minuteline/constant.py +89 -0
- xfintech/data/source/baostock/stock/minuteline/minuteline.py +163 -0
- xfintech/data/source/baostock/stock/minuteline/tests/__init__.py +0 -0
- xfintech/data/source/baostock/stock/minuteline/tests/test_class_minuteline_all.py +582 -0
- xfintech/data/source/baostock/stock/stock/__init__.py +19 -0
- xfintech/data/source/baostock/stock/stock/constant.py +55 -0
- xfintech/data/source/baostock/stock/stock/stock.py +149 -0
- xfintech/data/source/baostock/stock/stock/tests/__init__.py +0 -0
- xfintech/data/source/baostock/stock/stock/tests/test_class_stock_all.py +508 -0
- xfintech/data/source/baostock/stock/stockinfo/__init__.py +5 -0
- xfintech/data/source/baostock/stock/stockinfo/constant.py +66 -0
- xfintech/data/source/baostock/stock/stockinfo/stockinfo.py +176 -0
- xfintech/data/source/baostock/stock/stockinfo/tests/__init__.py +1 -0
- xfintech/data/source/baostock/stock/stockinfo/tests/test_class_stockinfo_all.py +617 -0
- xfintech/data/source/baostock/stock/sz50stock/__init__.py +3 -0
- xfintech/data/source/baostock/stock/sz50stock/constant.py +49 -0
- xfintech/data/source/baostock/stock/sz50stock/sz50stock.py +133 -0
- xfintech/data/source/baostock/stock/sz50stock/tests/__init__.py +1 -0
- xfintech/data/source/baostock/stock/sz50stock/tests/test_class_sz50stock_all.py +397 -0
- xfintech/data/source/baostock/stock/tradedate/__init__.py +19 -0
- xfintech/data/source/baostock/stock/tradedate/constant.py +72 -0
- xfintech/data/source/baostock/stock/tradedate/tests/__init__.py +0 -0
- xfintech/data/source/baostock/stock/tradedate/tests/test_class_tradedate_all.py +695 -0
- xfintech/data/source/baostock/stock/tradedate/tradedate.py +208 -0
- xfintech/data/source/baostock/stock/zz500stock/__init__.py +3 -0
- xfintech/data/source/baostock/stock/zz500stock/constant.py +55 -0
- xfintech/data/source/baostock/stock/zz500stock/tests/__init__.py +1 -0
- xfintech/data/source/baostock/stock/zz500stock/tests/test_class_zz500stock_all.py +421 -0
- xfintech/data/source/baostock/stock/zz500stock/zz500stock.py +133 -0
- xfintech/data/source/tushare/__init__.py +61 -0
- xfintech/data/source/tushare/job/__init__.py +5 -0
- xfintech/data/source/tushare/job/job.py +257 -0
- xfintech/data/source/tushare/job/tests/test_class_tusharejob_all.py +589 -0
- xfintech/data/source/tushare/session/__init__.py +5 -0
- xfintech/data/source/tushare/session/relay.py +231 -0
- xfintech/data/source/tushare/session/session.py +239 -0
- xfintech/data/source/tushare/session/tests/test_class_relay_all.py +719 -0
- xfintech/data/source/tushare/session/tests/test_class_session_all.py +705 -0
- xfintech/data/source/tushare/stock/__init__.py +55 -0
- xfintech/data/source/tushare/stock/adjfactor/__init__.py +19 -0
- xfintech/data/source/tushare/stock/adjfactor/adjfactor.py +150 -0
- xfintech/data/source/tushare/stock/adjfactor/constant.py +71 -0
- xfintech/data/source/tushare/stock/adjfactor/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/adjfactor/tests/test_class_adjfactor_all.py +372 -0
- xfintech/data/source/tushare/stock/capflow/__init__.py +19 -0
- xfintech/data/source/tushare/stock/capflow/capflow.py +171 -0
- xfintech/data/source/tushare/stock/capflow/constant.py +105 -0
- xfintech/data/source/tushare/stock/capflow/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/capflow/tests/test_class_capflow_all.py +589 -0
- xfintech/data/source/tushare/stock/capflowdc/__init__.py +19 -0
- xfintech/data/source/tushare/stock/capflowdc/capflowdc.py +167 -0
- xfintech/data/source/tushare/stock/capflowdc/constant.py +95 -0
- xfintech/data/source/tushare/stock/capflowdc/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/capflowdc/tests/test_class_capflowdc_all.py +814 -0
- xfintech/data/source/tushare/stock/capflowths/__init__.py +19 -0
- xfintech/data/source/tushare/stock/capflowths/capflowths.py +173 -0
- xfintech/data/source/tushare/stock/capflowths/constant.py +92 -0
- xfintech/data/source/tushare/stock/capflowths/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/capflowths/tests/test_class_capflowths_all.py +551 -0
- xfintech/data/source/tushare/stock/company/__init__.py +19 -0
- xfintech/data/source/tushare/stock/company/company.py +188 -0
- xfintech/data/source/tushare/stock/company/constant.py +92 -0
- xfintech/data/source/tushare/stock/company/tests/__init__.py +1 -0
- xfintech/data/source/tushare/stock/company/tests/test_class_company_all.py +829 -0
- xfintech/data/source/tushare/stock/companybusiness/__init__.py +21 -0
- xfintech/data/source/tushare/stock/companybusiness/companybusiness.py +183 -0
- xfintech/data/source/tushare/stock/companybusiness/constant.py +91 -0
- xfintech/data/source/tushare/stock/companybusiness/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/companybusiness/tests/test_class_companybusiness_all.py +633 -0
- xfintech/data/source/tushare/stock/companycashflow/__init__.py +21 -0
- xfintech/data/source/tushare/stock/companycashflow/companycashflow.py +277 -0
- xfintech/data/source/tushare/stock/companycashflow/constant.py +293 -0
- xfintech/data/source/tushare/stock/companycashflow/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/companycashflow/tests/test_class_companycashflow_all.py +619 -0
- xfintech/data/source/tushare/stock/companydebt/__init__.py +19 -0
- xfintech/data/source/tushare/stock/companydebt/companydebt.py +339 -0
- xfintech/data/source/tushare/stock/companydebt/constant.py +403 -0
- xfintech/data/source/tushare/stock/companydebt/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/companydebt/tests/test_class_companydebt_all.py +655 -0
- xfintech/data/source/tushare/stock/companyoverview/__init__.py +21 -0
- xfintech/data/source/tushare/stock/companyoverview/companyoverview.py +214 -0
- xfintech/data/source/tushare/stock/companyoverview/constant.py +152 -0
- xfintech/data/source/tushare/stock/companyoverview/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/companyoverview/tests/test_class_companyoverview_all.py +647 -0
- xfintech/data/source/tushare/stock/companyprofit/__init__.py +21 -0
- xfintech/data/source/tushare/stock/companyprofit/companyprofit.py +272 -0
- xfintech/data/source/tushare/stock/companyprofit/constant.py +259 -0
- xfintech/data/source/tushare/stock/companyprofit/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/companyprofit/tests/test_class_companyprofit_all.py +635 -0
- xfintech/data/source/tushare/stock/conceptcapflowdc/__init__.py +21 -0
- xfintech/data/source/tushare/stock/conceptcapflowdc/conceptcapflowdc.py +175 -0
- xfintech/data/source/tushare/stock/conceptcapflowdc/constant.py +106 -0
- xfintech/data/source/tushare/stock/conceptcapflowdc/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/conceptcapflowdc/tests/test_class_conceptcapflowdc_all.py +568 -0
- xfintech/data/source/tushare/stock/conceptcapflowths/__init__.py +21 -0
- xfintech/data/source/tushare/stock/conceptcapflowths/conceptcapflowths.py +188 -0
- xfintech/data/source/tushare/stock/conceptcapflowths/constant.py +89 -0
- xfintech/data/source/tushare/stock/conceptcapflowths/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/conceptcapflowths/tests/test_class_conceptcapflowths_all.py +516 -0
- xfintech/data/source/tushare/stock/dayline/__init__.py +19 -0
- xfintech/data/source/tushare/stock/dayline/constant.py +87 -0
- xfintech/data/source/tushare/stock/dayline/dayline.py +177 -0
- xfintech/data/source/tushare/stock/dayline/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/dayline/tests/test_class_dayline_all.py +585 -0
- xfintech/data/source/tushare/stock/industrycapflowths/__init__.py +21 -0
- xfintech/data/source/tushare/stock/industrycapflowths/constant.py +89 -0
- xfintech/data/source/tushare/stock/industrycapflowths/industrycapflowths.py +192 -0
- xfintech/data/source/tushare/stock/industrycapflowths/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/industrycapflowths/tests/test_class_industrycapflowths_all.py +683 -0
- xfintech/data/source/tushare/stock/marketindexcapflowdc/__init__.py +21 -0
- xfintech/data/source/tushare/stock/marketindexcapflowdc/constant.py +90 -0
- xfintech/data/source/tushare/stock/marketindexcapflowdc/marketindexcapflowdc.py +173 -0
- xfintech/data/source/tushare/stock/marketindexcapflowdc/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/marketindexcapflowdc/tests/test_class_marketindexcapflowdc_all.py +793 -0
- xfintech/data/source/tushare/stock/monthline/__init__.py +19 -0
- xfintech/data/source/tushare/stock/monthline/constant.py +87 -0
- xfintech/data/source/tushare/stock/monthline/monthline.py +180 -0
- xfintech/data/source/tushare/stock/monthline/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/monthline/tests/test_class_monthline_all.py +574 -0
- xfintech/data/source/tushare/stock/stock/__init__.py +19 -0
- xfintech/data/source/tushare/stock/stock/constant.py +105 -0
- xfintech/data/source/tushare/stock/stock/stock.py +193 -0
- xfintech/data/source/tushare/stock/stock/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/stock/tests/test_class_stock_all.py +788 -0
- xfintech/data/source/tushare/stock/stockdividend/__init__.py +21 -0
- xfintech/data/source/tushare/stock/stockdividend/constant.py +111 -0
- xfintech/data/source/tushare/stock/stockdividend/stockdividend.py +180 -0
- xfintech/data/source/tushare/stock/stockdividend/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/stockdividend/tests/test_class_stockdividend_all.py +725 -0
- xfintech/data/source/tushare/stock/stockinfo/__init__.py +19 -0
- xfintech/data/source/tushare/stock/stockinfo/constant.py +104 -0
- xfintech/data/source/tushare/stock/stockinfo/stockinfo.py +208 -0
- xfintech/data/source/tushare/stock/stockinfo/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/stockinfo/tests/test_class_stockinfo_all.py +881 -0
- xfintech/data/source/tushare/stock/stockipo/__init__.py +19 -0
- xfintech/data/source/tushare/stock/stockipo/constant.py +90 -0
- xfintech/data/source/tushare/stock/stockipo/stockipo.py +234 -0
- xfintech/data/source/tushare/stock/stockipo/tests/__init__.py +1 -0
- xfintech/data/source/tushare/stock/stockipo/tests/test_class_stockipo_all.py +750 -0
- xfintech/data/source/tushare/stock/stockpledge/__init__.py +19 -0
- xfintech/data/source/tushare/stock/stockpledge/constant.py +72 -0
- xfintech/data/source/tushare/stock/stockpledge/stockpledge.py +158 -0
- xfintech/data/source/tushare/stock/stockpledge/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/stockpledge/tests/test_class_stockpledge_all.py +664 -0
- xfintech/data/source/tushare/stock/stockpledgedetail/__init__.py +21 -0
- xfintech/data/source/tushare/stock/stockpledgedetail/constant.py +85 -0
- xfintech/data/source/tushare/stock/stockpledgedetail/stockpledgedetail.py +171 -0
- xfintech/data/source/tushare/stock/stockpledgedetail/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/stockpledgedetail/tests/test_class_stockpledgedetail_all.py +112 -0
- xfintech/data/source/tushare/stock/stockst/__init__.py +19 -0
- xfintech/data/source/tushare/stock/stockst/constant.py +80 -0
- xfintech/data/source/tushare/stock/stockst/stockst.py +189 -0
- xfintech/data/source/tushare/stock/stockst/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/stockst/tests/test_class_stockst_all.py +693 -0
- xfintech/data/source/tushare/stock/stocksuspend/__init__.py +21 -0
- xfintech/data/source/tushare/stock/stocksuspend/constant.py +75 -0
- xfintech/data/source/tushare/stock/stocksuspend/stocksuspend.py +151 -0
- xfintech/data/source/tushare/stock/stocksuspend/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/stocksuspend/tests/test_class_stocksuspend_all.py +626 -0
- xfintech/data/source/tushare/stock/techindex/__init__.py +19 -0
- xfintech/data/source/tushare/stock/techindex/constant.py +600 -0
- xfintech/data/source/tushare/stock/techindex/techindex.py +314 -0
- xfintech/data/source/tushare/stock/techindex/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/techindex/tests/test_class_techindex_all.py +576 -0
- xfintech/data/source/tushare/stock/tradedate/__init__.py +19 -0
- xfintech/data/source/tushare/stock/tradedate/constant.py +93 -0
- xfintech/data/source/tushare/stock/tradedate/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/tradedate/tests/test_class_tradedate_all.py +947 -0
- xfintech/data/source/tushare/stock/tradedate/tradedate.py +234 -0
- xfintech/data/source/tushare/stock/weekline/__init__.py +19 -0
- xfintech/data/source/tushare/stock/weekline/constant.py +87 -0
- xfintech/data/source/tushare/stock/weekline/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/weekline/tests/test_class_weekline_all.py +575 -0
- xfintech/data/source/tushare/stock/weekline/weekline.py +182 -0
- xfintech/fabric/__init__.py +18 -0
- xfintech/fabric/column/__init__.py +7 -0
- xfintech/fabric/column/info.py +202 -0
- xfintech/fabric/column/kind.py +102 -0
- xfintech/fabric/column/tests/__init__.py +0 -0
- xfintech/fabric/column/tests/test_class_info_all.py +207 -0
- xfintech/fabric/column/tests/test_class_kind_all.py +80 -0
- xfintech/fabric/table/__init__.py +5 -0
- xfintech/fabric/table/info.py +263 -0
- xfintech/fabric/table/tests/__init__.py +0 -0
- xfintech/fabric/table/tests/test_class_info_all.py +547 -0
- xfintech/serde/__init__.py +35 -0
- xfintech/serde/common/__init__.py +9 -0
- xfintech/serde/common/dataformat.py +78 -0
- xfintech/serde/common/deserialiserlike.py +38 -0
- xfintech/serde/common/error.py +182 -0
- xfintech/serde/common/serialiserlike.py +38 -0
- xfintech/serde/common/tests/__init__.py +1 -0
- xfintech/serde/common/tests/test_class_dataformat_all.py +694 -0
- xfintech/serde/common/tests/test_class_deserialiserlike_all.py +500 -0
- xfintech/serde/common/tests/test_class_errors_all.py +518 -0
- xfintech/serde/common/tests/test_class_serialiserlike_all.py +401 -0
- xfintech/serde/deserialiser/__init__.py +7 -0
- xfintech/serde/deserialiser/pandas.py +113 -0
- xfintech/serde/deserialiser/python.py +68 -0
- xfintech/serde/deserialiser/tests/__init__.py +1 -0
- xfintech/serde/deserialiser/tests/test_class_pandasdeserialiser_all.py +503 -0
- xfintech/serde/deserialiser/tests/test_class_pythondeserialiser_all.py +570 -0
- xfintech/serde/serialiser/__init__.py +7 -0
- xfintech/serde/serialiser/pandas.py +116 -0
- xfintech/serde/serialiser/python.py +71 -0
- xfintech/serde/serialiser/tests/__init__.py +1 -0
- xfintech/serde/serialiser/tests/test_class_pandasserialiser_all.py +474 -0
- xfintech/serde/serialiser/tests/test_class_pythonserialiser_all.py +508 -0
|
@@ -0,0 +1,585 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Test suite for Dayline class
|
|
3
|
+
Tests cover initialization, data fetching, transformation, date handling, and utility methods
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from unittest.mock import MagicMock, patch
|
|
7
|
+
|
|
8
|
+
import pandas as pd
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
from xfintech.data.common.cache import Cache
|
|
12
|
+
from xfintech.data.common.coolant import Coolant
|
|
13
|
+
from xfintech.data.common.retry import Retry
|
|
14
|
+
from xfintech.data.source.tushare.session.session import Session
|
|
15
|
+
from xfintech.data.source.tushare.stock.dayline.constant import (
|
|
16
|
+
KEY,
|
|
17
|
+
NAME,
|
|
18
|
+
SOURCE,
|
|
19
|
+
TARGET,
|
|
20
|
+
)
|
|
21
|
+
from xfintech.data.source.tushare.stock.dayline.dayline import Dayline
|
|
22
|
+
|
|
23
|
+
# ============================================================================
|
|
24
|
+
# Fixtures
|
|
25
|
+
# ============================================================================
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@pytest.fixture
|
|
29
|
+
def mock_session():
|
|
30
|
+
"""Create a mock Tushare session"""
|
|
31
|
+
session = MagicMock(spec=Session)
|
|
32
|
+
session._credential = "test_token"
|
|
33
|
+
session.id = "test1234"
|
|
34
|
+
session.mode = "direct"
|
|
35
|
+
session.relay_url = None
|
|
36
|
+
session.relay_secret = None
|
|
37
|
+
session.connected = True
|
|
38
|
+
|
|
39
|
+
# Mock the connection object
|
|
40
|
+
mock_connection = MagicMock()
|
|
41
|
+
mock_connection.daily = MagicMock()
|
|
42
|
+
session.connection = mock_connection
|
|
43
|
+
|
|
44
|
+
return session
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@pytest.fixture
|
|
48
|
+
def sample_source_data():
|
|
49
|
+
"""Create sample source data in Tushare format"""
|
|
50
|
+
return pd.DataFrame(
|
|
51
|
+
{
|
|
52
|
+
"ts_code": ["000001.SZ", "000002.SZ", "600000.SH"],
|
|
53
|
+
"trade_date": ["20241201", "20241201", "20241129"],
|
|
54
|
+
"open": [10.50, 8.20, 15.30],
|
|
55
|
+
"high": [10.80, 8.45, 15.60],
|
|
56
|
+
"low": [10.30, 8.00, 15.10],
|
|
57
|
+
"close": [10.75, 8.35, 15.45],
|
|
58
|
+
"pre_close": [10.50, 8.20, 15.20],
|
|
59
|
+
"change": [0.25, 0.15, 0.25],
|
|
60
|
+
"pct_chg": [2.38, 1.83, 1.64],
|
|
61
|
+
"vol": [6250000.0, 4900000.0, 10500000.0],
|
|
62
|
+
"amount": [672500.0, 406000.0, 1622500.0],
|
|
63
|
+
}
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# ============================================================================
|
|
68
|
+
# Initialization Tests
|
|
69
|
+
# ============================================================================
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_dayline_initialization_basic(mock_session):
|
|
73
|
+
"""Test basic initialization"""
|
|
74
|
+
job = Dayline(session=mock_session)
|
|
75
|
+
|
|
76
|
+
assert job.name == NAME
|
|
77
|
+
assert job.key == KEY
|
|
78
|
+
assert job.source == SOURCE
|
|
79
|
+
assert job.target == TARGET
|
|
80
|
+
assert job.paginate.pagesize == 6000
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_dayline_initialization_with_params(mock_session):
|
|
84
|
+
"""Test initialization with params"""
|
|
85
|
+
params = {"ts_code": "000001.SZ", "start_date": "20240101"}
|
|
86
|
+
job = Dayline(session=mock_session, params=params)
|
|
87
|
+
|
|
88
|
+
assert job.params.ts_code == "000001.SZ"
|
|
89
|
+
assert job.params.start_date == "20240101"
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_dayline_initialization_with_all_components(mock_session):
|
|
93
|
+
"""Test initialization with all components"""
|
|
94
|
+
params = {"ts_code": "000001.SZ"}
|
|
95
|
+
coolant = Coolant(interval=0.2)
|
|
96
|
+
retry = Retry(retry=3)
|
|
97
|
+
cache = Cache(path="/tmp/test_cache")
|
|
98
|
+
|
|
99
|
+
job = Dayline(
|
|
100
|
+
session=mock_session,
|
|
101
|
+
params=params,
|
|
102
|
+
coolant=coolant,
|
|
103
|
+
retry=retry,
|
|
104
|
+
cache=cache,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
assert job.params.ts_code == "000001.SZ"
|
|
108
|
+
assert job.coolant.interval == 0.2
|
|
109
|
+
assert job.retry.retry == 3
|
|
110
|
+
assert job.cache is not None
|
|
111
|
+
assert isinstance(job.cache, Cache)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def test_dayline_name_and_key():
|
|
115
|
+
"""Test name and key constants"""
|
|
116
|
+
assert NAME == "dayline"
|
|
117
|
+
assert KEY == "/tushare/dayline"
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def test_dayline_source_schema():
|
|
121
|
+
"""Test source schema has all required columns"""
|
|
122
|
+
assert SOURCE is not None
|
|
123
|
+
assert SOURCE.desc == "A股日线行情数据(Tushare格式)"
|
|
124
|
+
|
|
125
|
+
column_names = SOURCE.columns
|
|
126
|
+
assert "ts_code" in column_names
|
|
127
|
+
assert "trade_date" in column_names
|
|
128
|
+
assert "open" in column_names
|
|
129
|
+
assert "high" in column_names
|
|
130
|
+
assert "low" in column_names
|
|
131
|
+
assert "close" in column_names
|
|
132
|
+
assert "vol" in column_names
|
|
133
|
+
assert "amount" in column_names
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def test_dayline_target_schema():
|
|
137
|
+
"""Test target schema has all required columns"""
|
|
138
|
+
assert TARGET is not None
|
|
139
|
+
assert TARGET.desc == "A股日线行情数据(xfintech格式)"
|
|
140
|
+
|
|
141
|
+
column_names = TARGET.columns
|
|
142
|
+
assert "code" in column_names
|
|
143
|
+
assert "date" in column_names
|
|
144
|
+
assert "datecode" in column_names
|
|
145
|
+
assert "open" in column_names
|
|
146
|
+
assert "close" in column_names
|
|
147
|
+
assert "percent_change" in column_names
|
|
148
|
+
assert "volume" in column_names
|
|
149
|
+
assert "amount" in column_names
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
# ============================================================================
|
|
153
|
+
# Transform Tests
|
|
154
|
+
# ============================================================================
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def test_dayline_transform_basic(mock_session, sample_source_data):
|
|
158
|
+
"""Test basic data transformation"""
|
|
159
|
+
job = Dayline(session=mock_session)
|
|
160
|
+
result = job.transform(sample_source_data)
|
|
161
|
+
|
|
162
|
+
assert len(result) == 3
|
|
163
|
+
assert "code" in result.columns
|
|
164
|
+
assert "date" in result.columns
|
|
165
|
+
assert "datecode" in result.columns
|
|
166
|
+
assert result.iloc[0]["code"] == "000001.SZ"
|
|
167
|
+
assert result.iloc[0]["datecode"] == "20241201"
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def test_dayline_transform_date_conversion(mock_session, sample_source_data):
|
|
171
|
+
"""Test date field conversions"""
|
|
172
|
+
job = Dayline(session=mock_session)
|
|
173
|
+
result = job.transform(sample_source_data)
|
|
174
|
+
|
|
175
|
+
# Check date format (YYYY-MM-DD)
|
|
176
|
+
assert result.iloc[0]["date"] == "2024-12-01"
|
|
177
|
+
assert result.iloc[1]["date"] == "2024-12-01"
|
|
178
|
+
assert result.iloc[2]["date"] == "2024-11-29"
|
|
179
|
+
|
|
180
|
+
# Check datecode format (YYYYMMDD)
|
|
181
|
+
assert result.iloc[0]["datecode"] == "20241201"
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def test_dayline_transform_price_fields(mock_session, sample_source_data):
|
|
185
|
+
"""Test price field transformations"""
|
|
186
|
+
job = Dayline(session=mock_session)
|
|
187
|
+
result = job.transform(sample_source_data)
|
|
188
|
+
|
|
189
|
+
row = result.iloc[0]
|
|
190
|
+
assert row["open"] == 10.50
|
|
191
|
+
assert row["high"] == 10.80
|
|
192
|
+
assert row["low"] == 10.30
|
|
193
|
+
assert row["close"] == 10.75
|
|
194
|
+
assert row["pre_close"] == 10.50
|
|
195
|
+
assert row["change"] == 0.25
|
|
196
|
+
assert row["percent_change"] == 2.38
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def test_dayline_transform_volume_fields(mock_session, sample_source_data):
|
|
200
|
+
"""Test volume field transformations"""
|
|
201
|
+
job = Dayline(session=mock_session)
|
|
202
|
+
result = job.transform(sample_source_data)
|
|
203
|
+
|
|
204
|
+
row = result.iloc[0]
|
|
205
|
+
assert row["volume"] == 6250000.0
|
|
206
|
+
assert row["amount"] == 672500.0
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def test_dayline_transform_empty_data(mock_session):
|
|
210
|
+
"""Test transform with empty data"""
|
|
211
|
+
job = Dayline(session=mock_session)
|
|
212
|
+
|
|
213
|
+
# Test with None
|
|
214
|
+
result = job.transform(None)
|
|
215
|
+
assert result.empty
|
|
216
|
+
assert len(result.columns) == len(TARGET.columns)
|
|
217
|
+
|
|
218
|
+
# Test with empty DataFrame
|
|
219
|
+
empty_df = pd.DataFrame()
|
|
220
|
+
result = job.transform(empty_df)
|
|
221
|
+
assert result.empty
|
|
222
|
+
assert len(result.columns) == len(TARGET.columns)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def test_dayline_transform_invalid_data(mock_session):
|
|
226
|
+
"""Test transform with invalid numeric values"""
|
|
227
|
+
data = pd.DataFrame(
|
|
228
|
+
{
|
|
229
|
+
"ts_code": ["000001.SZ", "000002.SZ"],
|
|
230
|
+
"trade_date": ["20241201", "invalid_date"],
|
|
231
|
+
"open": [10.50, "invalid"],
|
|
232
|
+
"high": [10.80, 8.45],
|
|
233
|
+
"low": [10.30, 8.00],
|
|
234
|
+
"close": [10.75, 8.35],
|
|
235
|
+
"pre_close": [10.50, 8.20],
|
|
236
|
+
"change": [0.25, 0.15],
|
|
237
|
+
"pct_chg": [2.38, 1.83],
|
|
238
|
+
"vol": [6250000.0, 4900000.0],
|
|
239
|
+
"amount": [672500.0, 406000.0],
|
|
240
|
+
}
|
|
241
|
+
)
|
|
242
|
+
job = Dayline(session=mock_session)
|
|
243
|
+
result = job.transform(data)
|
|
244
|
+
|
|
245
|
+
# Should handle invalid data gracefully
|
|
246
|
+
assert len(result) == 2
|
|
247
|
+
assert pd.isna(result.iloc[1]["date"]) # Invalid date
|
|
248
|
+
assert pd.isna(result.iloc[1]["open"]) # Invalid numeric
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def test_dayline_transform_duplicate_removal(mock_session):
|
|
252
|
+
"""Test that duplicates are removed"""
|
|
253
|
+
data = pd.DataFrame(
|
|
254
|
+
{
|
|
255
|
+
"ts_code": ["000001.SZ", "000001.SZ", "000002.SZ"],
|
|
256
|
+
"trade_date": ["20241201", "20241201", "20241201"],
|
|
257
|
+
"open": [10.50, 10.50, 8.20],
|
|
258
|
+
"high": [10.80, 10.80, 8.45],
|
|
259
|
+
"low": [10.30, 10.30, 8.00],
|
|
260
|
+
"close": [10.75, 10.75, 8.35],
|
|
261
|
+
"pre_close": [10.50, 10.50, 8.20],
|
|
262
|
+
"change": [0.25, 0.25, 0.15],
|
|
263
|
+
"pct_chg": [2.38, 2.38, 1.83],
|
|
264
|
+
"vol": [6250000.0, 6250000.0, 4900000.0],
|
|
265
|
+
"amount": [672500.0, 672500.0, 406000.0],
|
|
266
|
+
}
|
|
267
|
+
)
|
|
268
|
+
job = Dayline(session=mock_session)
|
|
269
|
+
result = job.transform(data)
|
|
270
|
+
|
|
271
|
+
# Duplicates should be removed
|
|
272
|
+
assert len(result) == 2
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def test_dayline_transform_sorting(mock_session):
|
|
276
|
+
"""Test that result is sorted by code and date"""
|
|
277
|
+
data = pd.DataFrame(
|
|
278
|
+
{
|
|
279
|
+
"ts_code": ["600000.SH", "000001.SZ", "000002.SZ"],
|
|
280
|
+
"trade_date": ["20241115", "20241201", "20241129"],
|
|
281
|
+
"open": [15.30, 10.50, 8.20],
|
|
282
|
+
"high": [15.60, 10.80, 8.45],
|
|
283
|
+
"low": [15.10, 10.30, 8.00],
|
|
284
|
+
"close": [15.45, 10.75, 8.35],
|
|
285
|
+
"pre_close": [15.20, 10.50, 8.20],
|
|
286
|
+
"change": [0.25, 0.25, 0.15],
|
|
287
|
+
"pct_chg": [1.64, 2.38, 1.83],
|
|
288
|
+
"vol": [10500000.0, 6250000.0, 4900000.0],
|
|
289
|
+
"amount": [1622500.0, 672500.0, 406000.0],
|
|
290
|
+
}
|
|
291
|
+
)
|
|
292
|
+
job = Dayline(session=mock_session)
|
|
293
|
+
result = job.transform(data)
|
|
294
|
+
|
|
295
|
+
# Should be sorted by code, then date
|
|
296
|
+
expected_order = ["000001.SZ", "000002.SZ", "600000.SH"]
|
|
297
|
+
actual_order = result["code"].tolist()
|
|
298
|
+
assert actual_order == expected_order
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
# ============================================================================
|
|
302
|
+
# Run Tests
|
|
303
|
+
# ============================================================================
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def test_dayline_run_basic(mock_session, sample_source_data):
|
|
307
|
+
"""Test basic run method"""
|
|
308
|
+
job = Dayline(session=mock_session)
|
|
309
|
+
|
|
310
|
+
with patch.object(job, "_fetchall", return_value=sample_source_data):
|
|
311
|
+
result = job.run()
|
|
312
|
+
|
|
313
|
+
assert isinstance(result, pd.DataFrame)
|
|
314
|
+
assert len(result) == 3
|
|
315
|
+
assert "code" in result.columns
|
|
316
|
+
assert "date" in result.columns
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def test_dayline_run_with_ts_code(mock_session, sample_source_data):
|
|
320
|
+
"""Test run with ts_code parameter"""
|
|
321
|
+
filtered_data = sample_source_data[sample_source_data["ts_code"] == "000001.SZ"]
|
|
322
|
+
|
|
323
|
+
job = Dayline(session=mock_session, params={"ts_code": "000001.SZ"})
|
|
324
|
+
|
|
325
|
+
with patch.object(job, "_fetchall", return_value=filtered_data):
|
|
326
|
+
result = job.run()
|
|
327
|
+
|
|
328
|
+
assert len(result) == 1
|
|
329
|
+
assert result["code"].iloc[0] == "000001.SZ"
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def test_dayline_run_with_multiple_ts_codes(mock_session, sample_source_data):
|
|
333
|
+
"""Test run with multiple ts_code parameter"""
|
|
334
|
+
job = Dayline(session=mock_session, params={"ts_code": "000001.SZ,000002.SZ"})
|
|
335
|
+
|
|
336
|
+
with patch.object(job, "_fetchall", return_value=sample_source_data) as mock_fetchall:
|
|
337
|
+
job.run()
|
|
338
|
+
call_kwargs = mock_fetchall.call_args[1]
|
|
339
|
+
assert call_kwargs["ts_code"] == "000001.SZ,000002.SZ"
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def test_dayline_run_with_trade_date_string(mock_session, sample_source_data):
|
|
343
|
+
"""Test run with trade_date as string"""
|
|
344
|
+
job = Dayline(session=mock_session, params={"trade_date": "20241201"})
|
|
345
|
+
|
|
346
|
+
with patch.object(job, "_fetchall", return_value=sample_source_data) as mock_fetchall:
|
|
347
|
+
job.run()
|
|
348
|
+
|
|
349
|
+
call_kwargs = mock_fetchall.call_args[1]
|
|
350
|
+
assert call_kwargs["trade_date"] == "20241201"
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def test_dayline_run_with_date_range_string(mock_session, sample_source_data):
|
|
354
|
+
"""Test run with start_date and end_date as strings"""
|
|
355
|
+
job = Dayline(
|
|
356
|
+
session=mock_session,
|
|
357
|
+
params={"start_date": "20241101", "end_date": "20241231"},
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
with patch.object(job, "_fetchall", return_value=sample_source_data) as mock_fetchall:
|
|
361
|
+
job.run()
|
|
362
|
+
|
|
363
|
+
call_kwargs = mock_fetchall.call_args[1]
|
|
364
|
+
assert call_kwargs["start_date"] == "20241101"
|
|
365
|
+
assert call_kwargs["end_date"] == "20241231"
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def test_dayline_run_calls_transform(mock_session, sample_source_data):
|
|
369
|
+
"""Test that run calls transform"""
|
|
370
|
+
job = Dayline(session=mock_session)
|
|
371
|
+
|
|
372
|
+
with patch.object(job, "_fetchall", return_value=sample_source_data):
|
|
373
|
+
with patch.object(job, "transform", wraps=job.transform) as mock_transform:
|
|
374
|
+
job.run()
|
|
375
|
+
|
|
376
|
+
mock_transform.assert_called_once()
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
# ============================================================================
|
|
380
|
+
# Cache Tests
|
|
381
|
+
# ============================================================================
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def test_dayline_cache_persistence(mock_session, sample_source_data):
|
|
385
|
+
"""Test that cache persists across runs"""
|
|
386
|
+
job = Dayline(session=mock_session, cache=True)
|
|
387
|
+
|
|
388
|
+
with patch.object(job, "_load_cache", return_value=None) as mock_load:
|
|
389
|
+
with patch.object(job, "_fetchall", return_value=sample_source_data) as mock_fetchall:
|
|
390
|
+
# First run - fetches data and caches it
|
|
391
|
+
result1 = job.run()
|
|
392
|
+
assert mock_fetchall.call_count == 1
|
|
393
|
+
assert mock_load.call_count == 1
|
|
394
|
+
|
|
395
|
+
# Second run - _load_cache still returns None, so _fetchall called again
|
|
396
|
+
result2 = job.run()
|
|
397
|
+
assert mock_fetchall.call_count == 2
|
|
398
|
+
assert mock_load.call_count == 2
|
|
399
|
+
|
|
400
|
+
pd.testing.assert_frame_equal(result1, result2)
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def test_dayline_params_identifier_uniqueness(mock_session):
|
|
404
|
+
"""Test that different params create different cache keys"""
|
|
405
|
+
job1 = Dayline(session=mock_session, params={"trade_date": "20241201"}, cache=True)
|
|
406
|
+
job2 = Dayline(session=mock_session, params={"trade_date": "20241129"}, cache=True)
|
|
407
|
+
|
|
408
|
+
assert job1.params.identifier != job2.params.identifier
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def test_dayline_without_cache(mock_session, sample_source_data):
|
|
412
|
+
"""Test that dayline works correctly without cache"""
|
|
413
|
+
job = Dayline(session=mock_session, cache=False)
|
|
414
|
+
|
|
415
|
+
with patch.object(job, "_fetchall", return_value=sample_source_data) as mock_fetchall:
|
|
416
|
+
job.run()
|
|
417
|
+
job.run()
|
|
418
|
+
|
|
419
|
+
# Should fetch twice (no caching)
|
|
420
|
+
assert mock_fetchall.call_count == 2
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
# ============================================================================
|
|
424
|
+
# List Methods Tests
|
|
425
|
+
# ============================================================================
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
def test_dayline_list_codes(mock_session, sample_source_data):
|
|
429
|
+
"""Test list_codes method"""
|
|
430
|
+
job = Dayline(session=mock_session, cache=False)
|
|
431
|
+
|
|
432
|
+
with patch.object(job, "_fetchall", return_value=sample_source_data):
|
|
433
|
+
codes = job.list_codes()
|
|
434
|
+
|
|
435
|
+
assert isinstance(codes, list)
|
|
436
|
+
assert len(codes) == 3
|
|
437
|
+
assert "000001.SZ" in codes
|
|
438
|
+
assert "000002.SZ" in codes
|
|
439
|
+
assert "600000.SH" in codes
|
|
440
|
+
assert codes == sorted(codes) # Should be sorted
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
def test_dayline_list_dates(mock_session, sample_source_data):
|
|
444
|
+
"""Test list_dates method"""
|
|
445
|
+
job = Dayline(session=mock_session, cache=False)
|
|
446
|
+
|
|
447
|
+
with patch.object(job, "_fetchall", return_value=sample_source_data):
|
|
448
|
+
dates = job.list_dates()
|
|
449
|
+
|
|
450
|
+
assert isinstance(dates, list)
|
|
451
|
+
assert len(dates) == 2 # Two unique dates
|
|
452
|
+
assert "2024-11-29" in dates
|
|
453
|
+
assert "2024-12-01" in dates
|
|
454
|
+
assert dates == sorted(dates) # Should be sorted
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
def test_dayline_list_codes_unique(mock_session):
|
|
458
|
+
"""Test that list_codes returns unique codes"""
|
|
459
|
+
data = pd.DataFrame(
|
|
460
|
+
{
|
|
461
|
+
"ts_code": ["000001.SZ", "000001.SZ", "000002.SZ"],
|
|
462
|
+
"trade_date": ["20241201", "20241129", "20241201"],
|
|
463
|
+
"open": [10.50, 10.60, 8.20],
|
|
464
|
+
"high": [10.80, 10.90, 8.45],
|
|
465
|
+
"low": [10.30, 10.40, 8.00],
|
|
466
|
+
"close": [10.75, 10.85, 8.35],
|
|
467
|
+
"pre_close": [10.50, 10.60, 8.20],
|
|
468
|
+
"change": [0.25, 0.25, 0.15],
|
|
469
|
+
"pct_chg": [2.38, 2.36, 1.83],
|
|
470
|
+
"vol": [6250000.0, 6500000.0, 4900000.0],
|
|
471
|
+
"amount": [672500.0, 702500.0, 406000.0],
|
|
472
|
+
}
|
|
473
|
+
)
|
|
474
|
+
|
|
475
|
+
job = Dayline(session=mock_session, cache=False)
|
|
476
|
+
|
|
477
|
+
with patch.object(job, "_fetchall", return_value=data):
|
|
478
|
+
codes = job.list_codes()
|
|
479
|
+
|
|
480
|
+
assert len(codes) == 2 # Should be unique
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
def test_dayline_list_dates_sorted(mock_session):
|
|
484
|
+
"""Test that list_dates returns sorted dates"""
|
|
485
|
+
data = pd.DataFrame(
|
|
486
|
+
{
|
|
487
|
+
"ts_code": ["000001.SZ", "000002.SZ", "600000.SH"],
|
|
488
|
+
"trade_date": ["20241229", "20241108", "20241115"],
|
|
489
|
+
"open": [10.50, 8.20, 15.30],
|
|
490
|
+
"high": [10.80, 8.45, 15.60],
|
|
491
|
+
"low": [10.30, 8.00, 15.10],
|
|
492
|
+
"close": [10.75, 8.35, 15.45],
|
|
493
|
+
"pre_close": [10.50, 8.20, 15.20],
|
|
494
|
+
"change": [0.25, 0.15, 0.25],
|
|
495
|
+
"pct_chg": [2.38, 1.83, 1.64],
|
|
496
|
+
"vol": [6250000.0, 4900000.0, 10500000.0],
|
|
497
|
+
"amount": [672500.0, 406000.0, 1622500.0],
|
|
498
|
+
}
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
job = Dayline(session=mock_session, cache=False)
|
|
502
|
+
|
|
503
|
+
with patch.object(job, "_fetchall", return_value=data):
|
|
504
|
+
dates = job.list_dates()
|
|
505
|
+
|
|
506
|
+
expected_dates = ["2024-11-08", "2024-11-15", "2024-12-29"]
|
|
507
|
+
assert dates == expected_dates
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
# ============================================================================
|
|
511
|
+
# Integration Tests
|
|
512
|
+
# ============================================================================
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
def test_dayline_full_workflow(mock_session, sample_source_data):
|
|
516
|
+
"""Test complete workflow from initialization to data retrieval"""
|
|
517
|
+
job = Dayline(
|
|
518
|
+
session=mock_session,
|
|
519
|
+
params={"ts_code": "000001.SZ", "start_date": "20241101", "end_date": "20241231"},
|
|
520
|
+
cache=False,
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
with patch.object(job, "_fetchall", return_value=sample_source_data):
|
|
524
|
+
result = job.run()
|
|
525
|
+
codes = job.list_codes()
|
|
526
|
+
dates = job.list_dates()
|
|
527
|
+
|
|
528
|
+
assert len(result) > 0
|
|
529
|
+
assert len(codes) > 0
|
|
530
|
+
assert len(dates) > 0
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
def test_dayline_large_dataset_handling(mock_session):
|
|
534
|
+
"""Test handling of large datasets"""
|
|
535
|
+
# Create large dataset
|
|
536
|
+
large_data = pd.DataFrame(
|
|
537
|
+
{
|
|
538
|
+
"ts_code": [f"{str(i).zfill(6)}.SZ" for i in range(1000)],
|
|
539
|
+
"trade_date": ["20241201"] * 1000,
|
|
540
|
+
"open": [10.50] * 1000,
|
|
541
|
+
"high": [10.80] * 1000,
|
|
542
|
+
"low": [10.30] * 1000,
|
|
543
|
+
"close": [10.75] * 1000,
|
|
544
|
+
"pre_close": [10.50] * 1000,
|
|
545
|
+
"change": [0.25] * 1000,
|
|
546
|
+
"pct_chg": [2.38] * 1000,
|
|
547
|
+
"vol": [6250000.0] * 1000,
|
|
548
|
+
"amount": [672500.0] * 1000,
|
|
549
|
+
}
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
job = Dayline(session=mock_session, cache=False)
|
|
553
|
+
|
|
554
|
+
with patch.object(job, "_fetchall", return_value=large_data):
|
|
555
|
+
result = job.run()
|
|
556
|
+
|
|
557
|
+
assert len(result) == 1000
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
def test_dayline_handles_missing_fields(mock_session):
|
|
561
|
+
"""Test handling of data with some missing fields"""
|
|
562
|
+
data = pd.DataFrame(
|
|
563
|
+
{
|
|
564
|
+
"ts_code": ["000001.SZ"],
|
|
565
|
+
"trade_date": ["20241201"],
|
|
566
|
+
"open": [10.50],
|
|
567
|
+
"high": [10.80],
|
|
568
|
+
"low": [10.30],
|
|
569
|
+
"close": [10.75],
|
|
570
|
+
"pre_close": [10.50],
|
|
571
|
+
"change": [0.25],
|
|
572
|
+
"pct_chg": [2.38],
|
|
573
|
+
"vol": [None], # Missing volume
|
|
574
|
+
"amount": [None], # Missing amount
|
|
575
|
+
}
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
job = Dayline(session=mock_session, cache=False)
|
|
579
|
+
|
|
580
|
+
with patch.object(job, "_fetchall", return_value=data):
|
|
581
|
+
result = job.run()
|
|
582
|
+
|
|
583
|
+
assert len(result) == 1
|
|
584
|
+
assert pd.isna(result.iloc[0]["volume"])
|
|
585
|
+
assert pd.isna(result.iloc[0]["amount"])
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from xfintech.data.source.tushare.stock.industrycapflowths.constant import (
|
|
4
|
+
KEY,
|
|
5
|
+
NAME,
|
|
6
|
+
PAGINATE,
|
|
7
|
+
SOURCE,
|
|
8
|
+
TARGET,
|
|
9
|
+
)
|
|
10
|
+
from xfintech.data.source.tushare.stock.industrycapflowths.industrycapflowths import (
|
|
11
|
+
IndustryCapflowTHS,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"IndustryCapflowTHS",
|
|
16
|
+
"KEY",
|
|
17
|
+
"NAME",
|
|
18
|
+
"PAGINATE",
|
|
19
|
+
"SOURCE",
|
|
20
|
+
"TARGET",
|
|
21
|
+
]
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from xfintech.data.common.paginate import Paginate
|
|
4
|
+
from xfintech.fabric.column.info import ColumnInfo
|
|
5
|
+
from xfintech.fabric.column.kind import ColumnKind
|
|
6
|
+
from xfintech.fabric.table.info import TableInfo
|
|
7
|
+
|
|
8
|
+
PROVIDER = "tushare"
|
|
9
|
+
SOURCE_NAME = "moneyflow_ind_ths"
|
|
10
|
+
URL = "https://tushare.pro/document/2?doc_id=343"
|
|
11
|
+
ARGS = {
|
|
12
|
+
"ts_code": {
|
|
13
|
+
"type": ColumnKind.STRING,
|
|
14
|
+
"required": "N",
|
|
15
|
+
"desc": "代码",
|
|
16
|
+
},
|
|
17
|
+
"trade_date": {
|
|
18
|
+
"type": ColumnKind.STRING,
|
|
19
|
+
"required": "N",
|
|
20
|
+
"desc": "交易日期(YYYYMMDD格式)",
|
|
21
|
+
},
|
|
22
|
+
"start_date": {
|
|
23
|
+
"type": ColumnKind.STRING,
|
|
24
|
+
"required": "N",
|
|
25
|
+
"desc": "开始日期",
|
|
26
|
+
},
|
|
27
|
+
"end_date": {
|
|
28
|
+
"type": ColumnKind.STRING,
|
|
29
|
+
"required": "N",
|
|
30
|
+
"desc": "结束日期",
|
|
31
|
+
},
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# Exported constants
|
|
35
|
+
NAME = "industrycapflowths"
|
|
36
|
+
KEY = "/tushare/industrycapflowths"
|
|
37
|
+
PAGINATE = Paginate(
|
|
38
|
+
pagesize=5000,
|
|
39
|
+
pagelimit=1000,
|
|
40
|
+
)
|
|
41
|
+
SOURCE = TableInfo(
|
|
42
|
+
desc="同花顺行业资金流向数据(tushare格式)",
|
|
43
|
+
meta={
|
|
44
|
+
"provider": PROVIDER,
|
|
45
|
+
"source": SOURCE_NAME,
|
|
46
|
+
"url": URL,
|
|
47
|
+
"args": ARGS,
|
|
48
|
+
"type": "partitioned",
|
|
49
|
+
"scale": "crosssection",
|
|
50
|
+
},
|
|
51
|
+
columns=[
|
|
52
|
+
ColumnInfo(name="trade_date", kind=ColumnKind.STRING, desc="交易日期"),
|
|
53
|
+
ColumnInfo(name="ts_code", kind=ColumnKind.STRING, desc="板块代码"),
|
|
54
|
+
ColumnInfo(name="industry", kind=ColumnKind.STRING, desc="板块名称"),
|
|
55
|
+
ColumnInfo(name="lead_stock", kind=ColumnKind.STRING, desc="领涨股票名称"),
|
|
56
|
+
ColumnInfo(name="close", kind=ColumnKind.FLOAT, desc="收盘指数"),
|
|
57
|
+
ColumnInfo(name="pct_change", kind=ColumnKind.FLOAT, desc="指数涨跌幅"),
|
|
58
|
+
ColumnInfo(name="company_num", kind=ColumnKind.INTEGER, desc="公司数量"),
|
|
59
|
+
ColumnInfo(name="pct_change_stock", kind=ColumnKind.FLOAT, desc="领涨股涨跌幅"),
|
|
60
|
+
ColumnInfo(name="close_price", kind=ColumnKind.FLOAT, desc="领涨股最新价"),
|
|
61
|
+
ColumnInfo(name="net_buy_amount", kind=ColumnKind.FLOAT, desc="流入资金(亿元)"),
|
|
62
|
+
ColumnInfo(name="net_sell_amount", kind=ColumnKind.FLOAT, desc="流出资金(亿元)"),
|
|
63
|
+
ColumnInfo(name="net_amount", kind=ColumnKind.FLOAT, desc="净额(亿元)"),
|
|
64
|
+
],
|
|
65
|
+
)
|
|
66
|
+
TARGET = TableInfo(
|
|
67
|
+
desc="同花顺行业资金流向数据(xfinbatch标准格式)",
|
|
68
|
+
meta={
|
|
69
|
+
"key": KEY,
|
|
70
|
+
"name": NAME,
|
|
71
|
+
"type": "partitioned",
|
|
72
|
+
"scale": "crosssection",
|
|
73
|
+
},
|
|
74
|
+
columns=[
|
|
75
|
+
ColumnInfo(name="code", kind=ColumnKind.STRING, desc="板块代码"),
|
|
76
|
+
ColumnInfo(name="date", kind=ColumnKind.STRING, desc="交易日期"),
|
|
77
|
+
ColumnInfo(name="datecode", kind=ColumnKind.STRING, desc="交易日期代码(YYYYMMDD)"),
|
|
78
|
+
ColumnInfo(name="industry", kind=ColumnKind.STRING, desc="板块名称"),
|
|
79
|
+
ColumnInfo(name="lead_stock", kind=ColumnKind.STRING, desc="领涨股票名称"),
|
|
80
|
+
ColumnInfo(name="close", kind=ColumnKind.FLOAT, desc="收盘指数"),
|
|
81
|
+
ColumnInfo(name="percent_change", kind=ColumnKind.FLOAT, desc="指数涨跌幅"),
|
|
82
|
+
ColumnInfo(name="company_num", kind=ColumnKind.INTEGER, desc="公司数量"),
|
|
83
|
+
ColumnInfo(name="percent_change_stock", kind=ColumnKind.FLOAT, desc="领涨股涨跌幅"),
|
|
84
|
+
ColumnInfo(name="close_price", kind=ColumnKind.FLOAT, desc="领涨股最新价"),
|
|
85
|
+
ColumnInfo(name="net_buy_amount", kind=ColumnKind.FLOAT, desc="流入资金(亿元)"),
|
|
86
|
+
ColumnInfo(name="net_sell_amount", kind=ColumnKind.FLOAT, desc="流出资金(亿元)"),
|
|
87
|
+
ColumnInfo(name="net_amount", kind=ColumnKind.FLOAT, desc="净额(亿元)"),
|
|
88
|
+
],
|
|
89
|
+
)
|