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
xfintech/data/source/tushare/stock/marketindexcapflowdc/tests/test_class_marketindexcapflowdc_all.py
ADDED
|
@@ -0,0 +1,793 @@
|
|
|
1
|
+
from datetime import date, datetime
|
|
2
|
+
from unittest.mock import MagicMock, patch
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from xfintech.data.common.cache import Cache
|
|
8
|
+
from xfintech.data.common.coolant import Coolant
|
|
9
|
+
from xfintech.data.common.retry import Retry
|
|
10
|
+
from xfintech.data.source.tushare.session import Session
|
|
11
|
+
from xfintech.data.source.tushare.stock.marketindexcapflowdc import (
|
|
12
|
+
KEY,
|
|
13
|
+
NAME,
|
|
14
|
+
SOURCE,
|
|
15
|
+
TARGET,
|
|
16
|
+
MarketIndexCapflowDC,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
# Fixtures
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@pytest.fixture
|
|
23
|
+
def mock_session():
|
|
24
|
+
"""Create a mock Tushare session"""
|
|
25
|
+
session = MagicMock(spec=Session)
|
|
26
|
+
session._credential = "test_token"
|
|
27
|
+
session.id = "test1234"
|
|
28
|
+
session.mode = "direct"
|
|
29
|
+
session.relay_url = None
|
|
30
|
+
session.relay_secret = None
|
|
31
|
+
session.connected = True
|
|
32
|
+
|
|
33
|
+
# Mock the connection object
|
|
34
|
+
mock_connection = MagicMock()
|
|
35
|
+
mock_connection.moneyflow_mkt_dc = MagicMock()
|
|
36
|
+
session.connection = mock_connection
|
|
37
|
+
|
|
38
|
+
return session
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# Test Class 1: Initialization Tests
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class TestMarketIndexCapflowDCInitialization:
|
|
45
|
+
"""Test MarketIndexCapflowDC class initialization and configuration."""
|
|
46
|
+
|
|
47
|
+
def test_name_constant(self):
|
|
48
|
+
"""Test NAME constant is set correctly."""
|
|
49
|
+
assert NAME == "marketindexcapflowdc"
|
|
50
|
+
|
|
51
|
+
def test_key_constant(self):
|
|
52
|
+
"""Test KEY constant is set correctly."""
|
|
53
|
+
assert KEY == "/tushare/marketindexcapflowdc"
|
|
54
|
+
|
|
55
|
+
def test_source_table_info(self):
|
|
56
|
+
"""Test SOURCE TableInfo configuration."""
|
|
57
|
+
assert SOURCE.desc == "东方财富大盘资金流向数据(tushare格式)"
|
|
58
|
+
assert SOURCE.meta["provider"] == "tushare"
|
|
59
|
+
assert SOURCE.meta["source"] == "moneyflow_mkt_dc"
|
|
60
|
+
assert SOURCE.meta["type"] == "partitioned"
|
|
61
|
+
assert SOURCE.meta["scale"] == "crosssection"
|
|
62
|
+
# Verify key columns exist
|
|
63
|
+
column_names = SOURCE.list_column_names()
|
|
64
|
+
assert "trade_date" in column_names
|
|
65
|
+
assert "close_sh" in column_names
|
|
66
|
+
assert "close_sz" in column_names
|
|
67
|
+
assert "net_amount" in column_names
|
|
68
|
+
|
|
69
|
+
def test_target_table_info(self):
|
|
70
|
+
"""Test TARGET TableInfo configuration."""
|
|
71
|
+
assert TARGET.desc == "东方财富大盘资金流向数据(xfinbatch标准格式)"
|
|
72
|
+
assert TARGET.meta["key"] == KEY
|
|
73
|
+
assert TARGET.meta["name"] == NAME
|
|
74
|
+
assert TARGET.meta["type"] == "partitioned"
|
|
75
|
+
assert TARGET.meta["scale"] == "crosssection"
|
|
76
|
+
# Verify transformed columns exist
|
|
77
|
+
column_names = TARGET.list_column_names()
|
|
78
|
+
assert "date" in column_names
|
|
79
|
+
assert "datecode" in column_names
|
|
80
|
+
assert "percent_change_sh" in column_names
|
|
81
|
+
assert "percent_change_sz" in column_names
|
|
82
|
+
|
|
83
|
+
def test_initialization_with_params(self, mock_session):
|
|
84
|
+
"""Test MarketIndexCapflowDC initialization with parameters."""
|
|
85
|
+
params = {"start_date": "20240901", "end_date": "20240930"}
|
|
86
|
+
job = MarketIndexCapflowDC(session=mock_session, params=params)
|
|
87
|
+
|
|
88
|
+
assert job.name == NAME
|
|
89
|
+
assert job.key == KEY
|
|
90
|
+
assert job.params.get("start_date") == "20240901"
|
|
91
|
+
assert job.params.get("end_date") == "20240930"
|
|
92
|
+
|
|
93
|
+
def test_initialization_with_optional_components(self, mock_session):
|
|
94
|
+
"""Test initialization with optional coolant, retry, and cache."""
|
|
95
|
+
coolant = Coolant(interval=1.0)
|
|
96
|
+
retry = Retry(retry=3)
|
|
97
|
+
cache = Cache(path="/tmp/test_cache")
|
|
98
|
+
|
|
99
|
+
job = MarketIndexCapflowDC(
|
|
100
|
+
session=mock_session,
|
|
101
|
+
params={"trade_date": "20240927"},
|
|
102
|
+
coolant=coolant,
|
|
103
|
+
retry=retry,
|
|
104
|
+
cache=cache,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
assert job.coolant.interval == 1.0
|
|
108
|
+
assert job.retry.retry == 3
|
|
109
|
+
assert job.cache is not None
|
|
110
|
+
assert isinstance(job.cache, Cache)
|
|
111
|
+
|
|
112
|
+
def test_initialization_minimal(self, mock_session):
|
|
113
|
+
"""Test minimal initialization with only required session."""
|
|
114
|
+
job = MarketIndexCapflowDC(session=mock_session)
|
|
115
|
+
|
|
116
|
+
assert job.name == NAME
|
|
117
|
+
assert job.key == KEY
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
# Test Class 2: Transform Tests
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class TestMarketIndexCapflowDCTransform:
|
|
124
|
+
"""Test the transform method that converts Tushare format to xfinbatch format."""
|
|
125
|
+
|
|
126
|
+
def test_transform_empty_dataframe(self, mock_session):
|
|
127
|
+
"""Test transform with empty DataFrame."""
|
|
128
|
+
job = MarketIndexCapflowDC(session=mock_session)
|
|
129
|
+
|
|
130
|
+
empty_df = pd.DataFrame()
|
|
131
|
+
result = job.transform(empty_df)
|
|
132
|
+
|
|
133
|
+
assert result.empty
|
|
134
|
+
assert list(result.columns) == TARGET.list_column_names()
|
|
135
|
+
|
|
136
|
+
def test_transform_none_input(self, mock_session):
|
|
137
|
+
"""Test transform with None input."""
|
|
138
|
+
job = MarketIndexCapflowDC(session=mock_session)
|
|
139
|
+
|
|
140
|
+
result = job.transform(None)
|
|
141
|
+
|
|
142
|
+
assert result.empty
|
|
143
|
+
assert list(result.columns) == TARGET.list_column_names()
|
|
144
|
+
|
|
145
|
+
def test_transform_basic_data(self, mock_session):
|
|
146
|
+
"""Test transform with basic data."""
|
|
147
|
+
job = MarketIndexCapflowDC(session=mock_session)
|
|
148
|
+
|
|
149
|
+
source_data = pd.DataFrame(
|
|
150
|
+
{
|
|
151
|
+
"trade_date": ["20240927"],
|
|
152
|
+
"close_sh": [3087.53],
|
|
153
|
+
"pct_change_sh": [2.89],
|
|
154
|
+
"close_sz": [9514.86],
|
|
155
|
+
"pct_change_sz": [6.71],
|
|
156
|
+
"net_amount": [17175101440.00],
|
|
157
|
+
"net_amount_rate": [15.5],
|
|
158
|
+
"buy_elg_amount": [17175101440.00],
|
|
159
|
+
"buy_elg_amount_rate": [8.2],
|
|
160
|
+
"buy_lg_amount": [-3564773376.00],
|
|
161
|
+
"buy_lg_amount_rate": [-2.1],
|
|
162
|
+
"buy_md_amount": [1234567890.00],
|
|
163
|
+
"buy_md_amount_rate": [1.5],
|
|
164
|
+
"buy_sm_amount": [-987654321.00],
|
|
165
|
+
"buy_sm_amount_rate": [-0.8],
|
|
166
|
+
}
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
result = job.transform(source_data)
|
|
170
|
+
|
|
171
|
+
assert not result.empty
|
|
172
|
+
assert len(result) == 1
|
|
173
|
+
assert result.iloc[0]["date"] == "2024-09-27"
|
|
174
|
+
assert result.iloc[0]["datecode"] == "20240927"
|
|
175
|
+
assert result.iloc[0]["close_sh"] == pytest.approx(3087.53)
|
|
176
|
+
assert result.iloc[0]["percent_change_sh"] == pytest.approx(2.89)
|
|
177
|
+
assert result.iloc[0]["close_sz"] == pytest.approx(9514.86)
|
|
178
|
+
assert result.iloc[0]["percent_change_sz"] == pytest.approx(6.71)
|
|
179
|
+
assert result.iloc[0]["net_amount"] == pytest.approx(17175101440.00)
|
|
180
|
+
|
|
181
|
+
def test_transform_multiple_dates(self, mock_session):
|
|
182
|
+
"""Test transform with multiple dates."""
|
|
183
|
+
job = MarketIndexCapflowDC(session=mock_session)
|
|
184
|
+
|
|
185
|
+
source_data = pd.DataFrame(
|
|
186
|
+
{
|
|
187
|
+
"trade_date": ["20240927", "20240926", "20240925"],
|
|
188
|
+
"close_sh": [3087.53, 3000.95, 2896.31],
|
|
189
|
+
"pct_change_sh": [2.89, 3.61, 1.16],
|
|
190
|
+
"close_sz": [9514.86, 8916.65, 8537.73],
|
|
191
|
+
"pct_change_sz": [6.71, 4.44, 1.21],
|
|
192
|
+
"net_amount": [17175101440.00, 18894807552.00, -4010342144.00],
|
|
193
|
+
"net_amount_rate": [15.5, 18.2, -3.5],
|
|
194
|
+
"buy_elg_amount": [17175101440.00, 18894807552.00, -4010342144.00],
|
|
195
|
+
"buy_elg_amount_rate": [8.2, 9.1, -2.0],
|
|
196
|
+
"buy_lg_amount": [-3564773376.00, -2446319616.00, -10390331392.00],
|
|
197
|
+
"buy_lg_amount_rate": [-2.1, -1.5, -5.2],
|
|
198
|
+
"buy_md_amount": [1234567890.00, 2345678901.00, 3456789012.00],
|
|
199
|
+
"buy_md_amount_rate": [1.5, 2.0, 2.5],
|
|
200
|
+
"buy_sm_amount": [-987654321.00, -1234567890.00, -2345678901.00],
|
|
201
|
+
"buy_sm_amount_rate": [-0.8, -1.0, -1.5],
|
|
202
|
+
}
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
result = job.transform(source_data)
|
|
206
|
+
|
|
207
|
+
assert len(result) == 3
|
|
208
|
+
# Verify sorted by date
|
|
209
|
+
assert result.iloc[0]["date"] == "2024-09-25"
|
|
210
|
+
assert result.iloc[1]["date"] == "2024-09-26"
|
|
211
|
+
assert result.iloc[2]["date"] == "2024-09-27"
|
|
212
|
+
|
|
213
|
+
def test_transform_numeric_conversion(self, mock_session):
|
|
214
|
+
"""Test that numeric fields are properly converted."""
|
|
215
|
+
job = MarketIndexCapflowDC(session=mock_session)
|
|
216
|
+
|
|
217
|
+
source_data = pd.DataFrame(
|
|
218
|
+
{
|
|
219
|
+
"trade_date": ["20240927"],
|
|
220
|
+
"close_sh": ["3087.53"], # String
|
|
221
|
+
"pct_change_sh": ["2.89"], # String
|
|
222
|
+
"close_sz": ["9514.86"], # String
|
|
223
|
+
"pct_change_sz": ["6.71"], # String
|
|
224
|
+
"net_amount": ["17175101440.00"], # String
|
|
225
|
+
"net_amount_rate": ["15.5"], # String
|
|
226
|
+
"buy_elg_amount": ["17175101440.00"], # String
|
|
227
|
+
"buy_elg_amount_rate": ["8.2"], # String
|
|
228
|
+
"buy_lg_amount": ["-3564773376.00"], # String
|
|
229
|
+
"buy_lg_amount_rate": ["-2.1"], # String
|
|
230
|
+
"buy_md_amount": ["1234567890.00"], # String
|
|
231
|
+
"buy_md_amount_rate": ["1.5"], # String
|
|
232
|
+
"buy_sm_amount": ["-987654321.00"], # String
|
|
233
|
+
"buy_sm_amount_rate": ["-0.8"], # String
|
|
234
|
+
}
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
result = job.transform(source_data)
|
|
238
|
+
|
|
239
|
+
# Verify all numeric fields are actually numeric
|
|
240
|
+
assert isinstance(result.iloc[0]["percent_change_sh"], (int, float))
|
|
241
|
+
assert isinstance(result.iloc[0]["close_sh"], (int, float))
|
|
242
|
+
assert isinstance(result.iloc[0]["net_amount"], (int, float))
|
|
243
|
+
assert result.iloc[0]["percent_change_sh"] == pytest.approx(2.89)
|
|
244
|
+
assert result.iloc[0]["close_sh"] == pytest.approx(3087.53)
|
|
245
|
+
|
|
246
|
+
def test_transform_handles_invalid_values(self, mock_session):
|
|
247
|
+
"""Test transform handles invalid numeric values gracefully."""
|
|
248
|
+
job = MarketIndexCapflowDC(session=mock_session)
|
|
249
|
+
|
|
250
|
+
source_data = pd.DataFrame(
|
|
251
|
+
{
|
|
252
|
+
"trade_date": ["20240927"],
|
|
253
|
+
"close_sh": ["invalid"],
|
|
254
|
+
"pct_change_sh": ["N/A"],
|
|
255
|
+
"close_sz": ["9514.86"],
|
|
256
|
+
"pct_change_sz": ["6.71"],
|
|
257
|
+
"net_amount": ["17175101440.00"],
|
|
258
|
+
"net_amount_rate": ["15.5"],
|
|
259
|
+
"buy_elg_amount": ["17175101440.00"],
|
|
260
|
+
"buy_elg_amount_rate": ["8.2"],
|
|
261
|
+
"buy_lg_amount": ["-3564773376.00"],
|
|
262
|
+
"buy_lg_amount_rate": ["-2.1"],
|
|
263
|
+
"buy_md_amount": ["1234567890.00"],
|
|
264
|
+
"buy_md_amount_rate": ["1.5"],
|
|
265
|
+
"buy_sm_amount": ["-987654321.00"],
|
|
266
|
+
"buy_sm_amount_rate": ["-0.8"],
|
|
267
|
+
}
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
result = job.transform(source_data)
|
|
271
|
+
|
|
272
|
+
# Should handle gracefully with NaN
|
|
273
|
+
assert pd.isna(result.iloc[0]["percent_change_sh"])
|
|
274
|
+
assert pd.isna(result.iloc[0]["close_sh"])
|
|
275
|
+
|
|
276
|
+
def test_transform_removes_duplicates(self, mock_session):
|
|
277
|
+
"""Test that transform removes duplicate rows."""
|
|
278
|
+
job = MarketIndexCapflowDC(session=mock_session)
|
|
279
|
+
|
|
280
|
+
# Create data with duplicates
|
|
281
|
+
source_data = pd.DataFrame(
|
|
282
|
+
{
|
|
283
|
+
"trade_date": ["20240927", "20240927"],
|
|
284
|
+
"close_sh": [3087.53, 3087.53],
|
|
285
|
+
"pct_change_sh": [2.89, 2.89],
|
|
286
|
+
"close_sz": [9514.86, 9514.86],
|
|
287
|
+
"pct_change_sz": [6.71, 6.71],
|
|
288
|
+
"net_amount": [17175101440.00, 17175101440.00],
|
|
289
|
+
"net_amount_rate": [15.5, 15.5],
|
|
290
|
+
"buy_elg_amount": [17175101440.00, 17175101440.00],
|
|
291
|
+
"buy_elg_amount_rate": [8.2, 8.2],
|
|
292
|
+
"buy_lg_amount": [-3564773376.00, -3564773376.00],
|
|
293
|
+
"buy_lg_amount_rate": [-2.1, -2.1],
|
|
294
|
+
"buy_md_amount": [1234567890.00, 1234567890.00],
|
|
295
|
+
"buy_md_amount_rate": [1.5, 1.5],
|
|
296
|
+
"buy_sm_amount": [-987654321.00, -987654321.00],
|
|
297
|
+
"buy_sm_amount_rate": [-0.8, -0.8],
|
|
298
|
+
}
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
result = job.transform(source_data)
|
|
302
|
+
|
|
303
|
+
# Should only have 1 row after deduplication
|
|
304
|
+
assert len(result) == 1
|
|
305
|
+
|
|
306
|
+
def test_transform_date_formatting(self, mock_session):
|
|
307
|
+
"""Test that dates are formatted correctly."""
|
|
308
|
+
job = MarketIndexCapflowDC(session=mock_session)
|
|
309
|
+
|
|
310
|
+
source_data = pd.DataFrame(
|
|
311
|
+
{
|
|
312
|
+
"trade_date": ["20240927", "20240926"],
|
|
313
|
+
"close_sh": [3087.53, 3000.95],
|
|
314
|
+
"pct_change_sh": [2.89, 3.61],
|
|
315
|
+
"close_sz": [9514.86, 8916.65],
|
|
316
|
+
"pct_change_sz": [6.71, 4.44],
|
|
317
|
+
"net_amount": [17175101440.00, 18894807552.00],
|
|
318
|
+
"net_amount_rate": [15.5, 18.2],
|
|
319
|
+
"buy_elg_amount": [17175101440.00, 18894807552.00],
|
|
320
|
+
"buy_elg_amount_rate": [8.2, 9.1],
|
|
321
|
+
"buy_lg_amount": [-3564773376.00, -2446319616.00],
|
|
322
|
+
"buy_lg_amount_rate": [-2.1, -1.5],
|
|
323
|
+
"buy_md_amount": [1234567890.00, 2345678901.00],
|
|
324
|
+
"buy_md_amount_rate": [1.5, 2.0],
|
|
325
|
+
"buy_sm_amount": [-987654321.00, -1234567890.00],
|
|
326
|
+
"buy_sm_amount_rate": [-0.8, -1.0],
|
|
327
|
+
}
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
result = job.transform(source_data)
|
|
331
|
+
|
|
332
|
+
# Result is sorted by date
|
|
333
|
+
assert result.iloc[0]["date"] == "2024-09-26"
|
|
334
|
+
assert result.iloc[0]["datecode"] == "20240926"
|
|
335
|
+
assert result.iloc[1]["date"] == "2024-09-27"
|
|
336
|
+
assert result.iloc[1]["datecode"] == "20240927"
|
|
337
|
+
|
|
338
|
+
def test_transform_all_target_columns_present(self, mock_session):
|
|
339
|
+
"""Test that all target columns are present in transformed data."""
|
|
340
|
+
job = MarketIndexCapflowDC(session=mock_session)
|
|
341
|
+
|
|
342
|
+
source_data = pd.DataFrame(
|
|
343
|
+
{
|
|
344
|
+
"trade_date": ["20240927"],
|
|
345
|
+
"close_sh": [3087.53],
|
|
346
|
+
"pct_change_sh": [2.89],
|
|
347
|
+
"close_sz": [9514.86],
|
|
348
|
+
"pct_change_sz": [6.71],
|
|
349
|
+
"net_amount": [17175101440.00],
|
|
350
|
+
"net_amount_rate": [15.5],
|
|
351
|
+
"buy_elg_amount": [17175101440.00],
|
|
352
|
+
"buy_elg_amount_rate": [8.2],
|
|
353
|
+
"buy_lg_amount": [-3564773376.00],
|
|
354
|
+
"buy_lg_amount_rate": [-2.1],
|
|
355
|
+
"buy_md_amount": [1234567890.00],
|
|
356
|
+
"buy_md_amount_rate": [1.5],
|
|
357
|
+
"buy_sm_amount": [-987654321.00],
|
|
358
|
+
"buy_sm_amount_rate": [-0.8],
|
|
359
|
+
}
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
result = job.transform(source_data)
|
|
363
|
+
|
|
364
|
+
expected_columns = TARGET.list_column_names()
|
|
365
|
+
assert list(result.columns) == expected_columns
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
# Test Class 3: Run Method Tests
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
class TestMarketIndexCapflowDCRun:
|
|
372
|
+
"""Test the _run method and parameter handling."""
|
|
373
|
+
|
|
374
|
+
def test_run_with_string_date_params(self, mock_session):
|
|
375
|
+
"""Test _run with string date parameters."""
|
|
376
|
+
# Mock the API response
|
|
377
|
+
mock_session.connection.moneyflow_mkt_dc.return_value = pd.DataFrame(
|
|
378
|
+
{
|
|
379
|
+
"trade_date": ["20240927"],
|
|
380
|
+
"close_sh": [3087.53],
|
|
381
|
+
"pct_change_sh": [2.89],
|
|
382
|
+
"close_sz": [9514.86],
|
|
383
|
+
"pct_change_sz": [6.71],
|
|
384
|
+
"net_amount": [17175101440.00],
|
|
385
|
+
"net_amount_rate": [15.5],
|
|
386
|
+
"buy_elg_amount": [17175101440.00],
|
|
387
|
+
"buy_elg_amount_rate": [8.2],
|
|
388
|
+
"buy_lg_amount": [-3564773376.00],
|
|
389
|
+
"buy_lg_amount_rate": [-2.1],
|
|
390
|
+
"buy_md_amount": [1234567890.00],
|
|
391
|
+
"buy_md_amount_rate": [1.5],
|
|
392
|
+
"buy_sm_amount": [-987654321.00],
|
|
393
|
+
"buy_sm_amount_rate": [-0.8],
|
|
394
|
+
}
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
job = MarketIndexCapflowDC(
|
|
398
|
+
session=mock_session,
|
|
399
|
+
params={"start_date": "20240901", "end_date": "20240930"},
|
|
400
|
+
cache=False,
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
result = job._run()
|
|
404
|
+
|
|
405
|
+
assert not result.empty
|
|
406
|
+
mock_session.connection.moneyflow_mkt_dc.assert_called_once()
|
|
407
|
+
call_kwargs = mock_session.connection.moneyflow_mkt_dc.call_args[1]
|
|
408
|
+
assert call_kwargs["start_date"] == "20240901"
|
|
409
|
+
assert call_kwargs["end_date"] == "20240930"
|
|
410
|
+
|
|
411
|
+
def test_run_with_datetime_params(self, mock_session):
|
|
412
|
+
"""Test _run converts datetime parameters correctly."""
|
|
413
|
+
mock_session.connection.moneyflow_mkt_dc.return_value = pd.DataFrame(
|
|
414
|
+
{
|
|
415
|
+
"trade_date": ["20240927"],
|
|
416
|
+
"close_sh": [3087.53],
|
|
417
|
+
"pct_change_sh": [2.89],
|
|
418
|
+
"close_sz": [9514.86],
|
|
419
|
+
"pct_change_sz": [6.71],
|
|
420
|
+
"net_amount": [17175101440.00],
|
|
421
|
+
"net_amount_rate": [15.5],
|
|
422
|
+
"buy_elg_amount": [17175101440.00],
|
|
423
|
+
"buy_elg_amount_rate": [8.2],
|
|
424
|
+
"buy_lg_amount": [-3564773376.00],
|
|
425
|
+
"buy_lg_amount_rate": [-2.1],
|
|
426
|
+
"buy_md_amount": [1234567890.00],
|
|
427
|
+
"buy_md_amount_rate": [1.5],
|
|
428
|
+
"buy_sm_amount": [-987654321.00],
|
|
429
|
+
"buy_sm_amount_rate": [-0.8],
|
|
430
|
+
}
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
job = MarketIndexCapflowDC(
|
|
434
|
+
session=mock_session,
|
|
435
|
+
params={"trade_date": datetime(2024, 9, 27)},
|
|
436
|
+
cache=False,
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
result = job._run()
|
|
440
|
+
|
|
441
|
+
assert not result.empty
|
|
442
|
+
call_kwargs = mock_session.connection.moneyflow_mkt_dc.call_args[1]
|
|
443
|
+
assert call_kwargs["trade_date"] == "20240927"
|
|
444
|
+
|
|
445
|
+
def test_run_with_date_params(self, mock_session):
|
|
446
|
+
"""Test _run converts date parameters correctly."""
|
|
447
|
+
mock_session.connection.moneyflow_mkt_dc.return_value = pd.DataFrame(
|
|
448
|
+
{
|
|
449
|
+
"trade_date": ["20240927"],
|
|
450
|
+
"close_sh": [3087.53],
|
|
451
|
+
"pct_change_sh": [2.89],
|
|
452
|
+
"close_sz": [9514.86],
|
|
453
|
+
"pct_change_sz": [6.71],
|
|
454
|
+
"net_amount": [17175101440.00],
|
|
455
|
+
"net_amount_rate": [15.5],
|
|
456
|
+
"buy_elg_amount": [17175101440.00],
|
|
457
|
+
"buy_elg_amount_rate": [8.2],
|
|
458
|
+
"buy_lg_amount": [-3564773376.00],
|
|
459
|
+
"buy_lg_amount_rate": [-2.1],
|
|
460
|
+
"buy_md_amount": [1234567890.00],
|
|
461
|
+
"buy_md_amount_rate": [1.5],
|
|
462
|
+
"buy_sm_amount": [-987654321.00],
|
|
463
|
+
"buy_sm_amount_rate": [-0.8],
|
|
464
|
+
}
|
|
465
|
+
)
|
|
466
|
+
|
|
467
|
+
job = MarketIndexCapflowDC(
|
|
468
|
+
session=mock_session,
|
|
469
|
+
params={"start_date": date(2024, 9, 1), "end_date": date(2024, 9, 30)},
|
|
470
|
+
cache=False,
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
result = job._run()
|
|
474
|
+
|
|
475
|
+
assert not result.empty
|
|
476
|
+
call_kwargs = mock_session.connection.moneyflow_mkt_dc.call_args[1]
|
|
477
|
+
assert call_kwargs["start_date"] == "20240901"
|
|
478
|
+
assert call_kwargs["end_date"] == "20240930"
|
|
479
|
+
|
|
480
|
+
def test_run_with_trade_date(self, mock_session):
|
|
481
|
+
"""Test _run with single trade_date parameter."""
|
|
482
|
+
mock_session.connection.moneyflow_mkt_dc.return_value = pd.DataFrame(
|
|
483
|
+
{
|
|
484
|
+
"trade_date": ["20240927"],
|
|
485
|
+
"close_sh": [3087.53],
|
|
486
|
+
"pct_change_sh": [2.89],
|
|
487
|
+
"close_sz": [9514.86],
|
|
488
|
+
"pct_change_sz": [6.71],
|
|
489
|
+
"net_amount": [17175101440.00],
|
|
490
|
+
"net_amount_rate": [15.5],
|
|
491
|
+
"buy_elg_amount": [17175101440.00],
|
|
492
|
+
"buy_elg_amount_rate": [8.2],
|
|
493
|
+
"buy_lg_amount": [-3564773376.00],
|
|
494
|
+
"buy_lg_amount_rate": [-2.1],
|
|
495
|
+
"buy_md_amount": [1234567890.00],
|
|
496
|
+
"buy_md_amount_rate": [1.5],
|
|
497
|
+
"buy_sm_amount": [-987654321.00],
|
|
498
|
+
"buy_sm_amount_rate": [-0.8],
|
|
499
|
+
}
|
|
500
|
+
)
|
|
501
|
+
|
|
502
|
+
job = MarketIndexCapflowDC(session=mock_session, params={"trade_date": "20240927"}, cache=False)
|
|
503
|
+
|
|
504
|
+
result = job._run()
|
|
505
|
+
|
|
506
|
+
assert not result.empty
|
|
507
|
+
call_kwargs = mock_session.connection.moneyflow_mkt_dc.call_args[1]
|
|
508
|
+
assert call_kwargs["trade_date"] == "20240927"
|
|
509
|
+
|
|
510
|
+
def test_run_empty_result(self, mock_session):
|
|
511
|
+
"""Test _run handles empty API result."""
|
|
512
|
+
mock_session.connection.moneyflow_mkt_dc.return_value = pd.DataFrame()
|
|
513
|
+
|
|
514
|
+
job = MarketIndexCapflowDC(session=mock_session, params={"trade_date": "20240101"}, cache=False)
|
|
515
|
+
|
|
516
|
+
result = job._run()
|
|
517
|
+
|
|
518
|
+
assert result.empty
|
|
519
|
+
assert list(result.columns) == TARGET.list_column_names()
|
|
520
|
+
|
|
521
|
+
def test_run_with_multiple_params(self, mock_session):
|
|
522
|
+
"""Test _run with multiple parameter types."""
|
|
523
|
+
mock_session.connection.moneyflow_mkt_dc.return_value = pd.DataFrame(
|
|
524
|
+
{
|
|
525
|
+
"trade_date": ["20240927"],
|
|
526
|
+
"close_sh": [3087.53],
|
|
527
|
+
"pct_change_sh": [2.89],
|
|
528
|
+
"close_sz": [9514.86],
|
|
529
|
+
"pct_change_sz": [6.71],
|
|
530
|
+
"net_amount": [17175101440.00],
|
|
531
|
+
"net_amount_rate": [15.5],
|
|
532
|
+
"buy_elg_amount": [17175101440.00],
|
|
533
|
+
"buy_elg_amount_rate": [8.2],
|
|
534
|
+
"buy_lg_amount": [-3564773376.00],
|
|
535
|
+
"buy_lg_amount_rate": [-2.1],
|
|
536
|
+
"buy_md_amount": [1234567890.00],
|
|
537
|
+
"buy_md_amount_rate": [1.5],
|
|
538
|
+
"buy_sm_amount": [-987654321.00],
|
|
539
|
+
"buy_sm_amount_rate": [-0.8],
|
|
540
|
+
}
|
|
541
|
+
)
|
|
542
|
+
|
|
543
|
+
job = MarketIndexCapflowDC(
|
|
544
|
+
session=mock_session,
|
|
545
|
+
params={
|
|
546
|
+
"start_date": date(2024, 9, 1),
|
|
547
|
+
"end_date": datetime(2024, 9, 30),
|
|
548
|
+
},
|
|
549
|
+
cache=False,
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
job._run()
|
|
553
|
+
|
|
554
|
+
call_kwargs = mock_session.connection.moneyflow_mkt_dc.call_args[1]
|
|
555
|
+
assert call_kwargs["start_date"] == "20240901"
|
|
556
|
+
assert call_kwargs["end_date"] == "20240930"
|
|
557
|
+
|
|
558
|
+
def test_run_api_called_with_correct_method(self, mock_session):
|
|
559
|
+
"""Test that _run calls moneyflow_mkt_dc API method."""
|
|
560
|
+
mock_session.connection.moneyflow_mkt_dc.return_value = pd.DataFrame(
|
|
561
|
+
{
|
|
562
|
+
"trade_date": ["20240927"],
|
|
563
|
+
"close_sh": [3087.53],
|
|
564
|
+
"pct_change_sh": [2.89],
|
|
565
|
+
"close_sz": [9514.86],
|
|
566
|
+
"pct_change_sz": [6.71],
|
|
567
|
+
"net_amount": [17175101440.00],
|
|
568
|
+
"net_amount_rate": [15.5],
|
|
569
|
+
"buy_elg_amount": [17175101440.00],
|
|
570
|
+
"buy_elg_amount_rate": [8.2],
|
|
571
|
+
"buy_lg_amount": [-3564773376.00],
|
|
572
|
+
"buy_lg_amount_rate": [-2.1],
|
|
573
|
+
"buy_md_amount": [1234567890.00],
|
|
574
|
+
"buy_md_amount_rate": [1.5],
|
|
575
|
+
"buy_sm_amount": [-987654321.00],
|
|
576
|
+
"buy_sm_amount_rate": [-0.8],
|
|
577
|
+
}
|
|
578
|
+
)
|
|
579
|
+
|
|
580
|
+
job = MarketIndexCapflowDC(session=mock_session, params={"trade_date": "20240927"}, cache=False)
|
|
581
|
+
|
|
582
|
+
job._run()
|
|
583
|
+
|
|
584
|
+
# Verify the correct API method was called
|
|
585
|
+
mock_session.connection.moneyflow_mkt_dc.assert_called_once()
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
# Test Class 4: Cache Tests
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
class TestMarketIndexCapflowDCCache:
|
|
592
|
+
"""Test caching functionality."""
|
|
593
|
+
|
|
594
|
+
def test_cache_enabled(self, mock_session):
|
|
595
|
+
"""Test that cache is used when enabled."""
|
|
596
|
+
cached_data = pd.DataFrame(
|
|
597
|
+
{
|
|
598
|
+
"date": ["2024-09-27"],
|
|
599
|
+
"datecode": ["20240927"],
|
|
600
|
+
"close_sh": [3087.53],
|
|
601
|
+
"percent_change_sh": [2.89],
|
|
602
|
+
"close_sz": [9514.86],
|
|
603
|
+
"percent_change_sz": [6.71],
|
|
604
|
+
"net_amount": [17175101440.00],
|
|
605
|
+
"net_amount_rate": [15.5],
|
|
606
|
+
"buy_elg_amount": [17175101440.00],
|
|
607
|
+
"buy_elg_amount_rate": [8.2],
|
|
608
|
+
"buy_lg_amount": [-3564773376.00],
|
|
609
|
+
"buy_lg_amount_rate": [-2.1],
|
|
610
|
+
"buy_md_amount": [1234567890.00],
|
|
611
|
+
"buy_md_amount_rate": [1.5],
|
|
612
|
+
"buy_sm_amount": [-987654321.00],
|
|
613
|
+
"buy_sm_amount_rate": [-0.8],
|
|
614
|
+
}
|
|
615
|
+
)
|
|
616
|
+
|
|
617
|
+
job = MarketIndexCapflowDC(session=mock_session, params={"trade_date": "20240927"}, cache=True)
|
|
618
|
+
|
|
619
|
+
# Mock _load_cache to return cached data
|
|
620
|
+
with patch.object(job, "_load_cache", return_value=cached_data):
|
|
621
|
+
result = job._run()
|
|
622
|
+
|
|
623
|
+
# Should return cached data without calling API
|
|
624
|
+
assert not result.empty
|
|
625
|
+
mock_session.connection.moneyflow_mkt_dc.assert_not_called()
|
|
626
|
+
|
|
627
|
+
def test_cache_disabled(self, mock_session):
|
|
628
|
+
"""Test that API is called when cache is disabled."""
|
|
629
|
+
mock_session.connection.moneyflow_mkt_dc.return_value = pd.DataFrame(
|
|
630
|
+
{
|
|
631
|
+
"trade_date": ["20240927"],
|
|
632
|
+
"close_sh": [3087.53],
|
|
633
|
+
"pct_change_sh": [2.89],
|
|
634
|
+
"close_sz": [9514.86],
|
|
635
|
+
"pct_change_sz": [6.71],
|
|
636
|
+
"net_amount": [17175101440.00],
|
|
637
|
+
"net_amount_rate": [15.5],
|
|
638
|
+
"buy_elg_amount": [17175101440.00],
|
|
639
|
+
"buy_elg_amount_rate": [8.2],
|
|
640
|
+
"buy_lg_amount": [-3564773376.00],
|
|
641
|
+
"buy_lg_amount_rate": [-2.1],
|
|
642
|
+
"buy_md_amount": [1234567890.00],
|
|
643
|
+
"buy_md_amount_rate": [1.5],
|
|
644
|
+
"buy_sm_amount": [-987654321.00],
|
|
645
|
+
"buy_sm_amount_rate": [-0.8],
|
|
646
|
+
}
|
|
647
|
+
)
|
|
648
|
+
|
|
649
|
+
job = MarketIndexCapflowDC(session=mock_session, params={"trade_date": "20240927"}, cache=False)
|
|
650
|
+
|
|
651
|
+
result = job._run()
|
|
652
|
+
|
|
653
|
+
# Should call API
|
|
654
|
+
assert not result.empty
|
|
655
|
+
mock_session.connection.moneyflow_mkt_dc.assert_called_once()
|
|
656
|
+
|
|
657
|
+
def test_cache_save_called(self, mock_session):
|
|
658
|
+
"""Test that cache save is called after successful run."""
|
|
659
|
+
mock_session.connection.moneyflow_mkt_dc.return_value = pd.DataFrame(
|
|
660
|
+
{
|
|
661
|
+
"trade_date": ["20240927"],
|
|
662
|
+
"close_sh": [3087.53],
|
|
663
|
+
"pct_change_sh": [2.89],
|
|
664
|
+
"close_sz": [9514.86],
|
|
665
|
+
"pct_change_sz": [6.71],
|
|
666
|
+
"net_amount": [17175101440.00],
|
|
667
|
+
"net_amount_rate": [15.5],
|
|
668
|
+
"buy_elg_amount": [17175101440.00],
|
|
669
|
+
"buy_elg_amount_rate": [8.2],
|
|
670
|
+
"buy_lg_amount": [-3564773376.00],
|
|
671
|
+
"buy_lg_amount_rate": [-2.1],
|
|
672
|
+
"buy_md_amount": [1234567890.00],
|
|
673
|
+
"buy_md_amount_rate": [1.5],
|
|
674
|
+
"buy_sm_amount": [-987654321.00],
|
|
675
|
+
"buy_sm_amount_rate": [-0.8],
|
|
676
|
+
}
|
|
677
|
+
)
|
|
678
|
+
|
|
679
|
+
job = MarketIndexCapflowDC(session=mock_session, params={"trade_date": "20240927"}, cache=True)
|
|
680
|
+
|
|
681
|
+
with patch.object(job, "_save_cache") as mock_save:
|
|
682
|
+
job._run()
|
|
683
|
+
|
|
684
|
+
# Should call save cache
|
|
685
|
+
mock_save.assert_called_once()
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
# Test Class 5: Integration Tests
|
|
689
|
+
|
|
690
|
+
|
|
691
|
+
class TestMarketIndexCapflowDCIntegration:
|
|
692
|
+
"""Integration tests combining multiple features."""
|
|
693
|
+
|
|
694
|
+
def test_full_workflow_single_date(self, mock_session):
|
|
695
|
+
"""Test complete workflow for single date query."""
|
|
696
|
+
mock_session.connection.moneyflow_mkt_dc.return_value = pd.DataFrame(
|
|
697
|
+
{
|
|
698
|
+
"trade_date": ["20240927"],
|
|
699
|
+
"close_sh": [3087.53],
|
|
700
|
+
"pct_change_sh": [2.89],
|
|
701
|
+
"close_sz": [9514.86],
|
|
702
|
+
"pct_change_sz": [6.71],
|
|
703
|
+
"net_amount": [17175101440.00],
|
|
704
|
+
"net_amount_rate": [15.5],
|
|
705
|
+
"buy_elg_amount": [17175101440.00],
|
|
706
|
+
"buy_elg_amount_rate": [8.2],
|
|
707
|
+
"buy_lg_amount": [-3564773376.00],
|
|
708
|
+
"buy_lg_amount_rate": [-2.1],
|
|
709
|
+
"buy_md_amount": [1234567890.00],
|
|
710
|
+
"buy_md_amount_rate": [1.5],
|
|
711
|
+
"buy_sm_amount": [-987654321.00],
|
|
712
|
+
"buy_sm_amount_rate": [-0.8],
|
|
713
|
+
}
|
|
714
|
+
)
|
|
715
|
+
|
|
716
|
+
job = MarketIndexCapflowDC(
|
|
717
|
+
session=mock_session,
|
|
718
|
+
params={"trade_date": "20240927"},
|
|
719
|
+
cache=False,
|
|
720
|
+
)
|
|
721
|
+
|
|
722
|
+
result = job.run()
|
|
723
|
+
|
|
724
|
+
assert len(result) == 1
|
|
725
|
+
assert result.iloc[0]["date"] == "2024-09-27"
|
|
726
|
+
assert result.iloc[0]["close_sh"] == pytest.approx(3087.53)
|
|
727
|
+
assert result.iloc[0]["net_amount"] == pytest.approx(17175101440.00)
|
|
728
|
+
|
|
729
|
+
def test_full_workflow_date_range(self, mock_session):
|
|
730
|
+
"""Test complete workflow for date range query."""
|
|
731
|
+
mock_session.connection.moneyflow_mkt_dc.return_value = pd.DataFrame(
|
|
732
|
+
{
|
|
733
|
+
"trade_date": ["20240927", "20240926", "20240925"],
|
|
734
|
+
"close_sh": [3087.53, 3000.95, 2896.31],
|
|
735
|
+
"pct_change_sh": [2.89, 3.61, 1.16],
|
|
736
|
+
"close_sz": [9514.86, 8916.65, 8537.73],
|
|
737
|
+
"pct_change_sz": [6.71, 4.44, 1.21],
|
|
738
|
+
"net_amount": [17175101440.00, 18894807552.00, -4010342144.00],
|
|
739
|
+
"net_amount_rate": [15.5, 18.2, -3.5],
|
|
740
|
+
"buy_elg_amount": [17175101440.00, 18894807552.00, -4010342144.00],
|
|
741
|
+
"buy_elg_amount_rate": [8.2, 9.1, -2.0],
|
|
742
|
+
"buy_lg_amount": [-3564773376.00, -2446319616.00, -10390331392.00],
|
|
743
|
+
"buy_lg_amount_rate": [-2.1, -1.5, -5.2],
|
|
744
|
+
"buy_md_amount": [1234567890.00, 2345678901.00, 3456789012.00],
|
|
745
|
+
"buy_md_amount_rate": [1.5, 2.0, 2.5],
|
|
746
|
+
"buy_sm_amount": [-987654321.00, -1234567890.00, -2345678901.00],
|
|
747
|
+
"buy_sm_amount_rate": [-0.8, -1.0, -1.5],
|
|
748
|
+
}
|
|
749
|
+
)
|
|
750
|
+
|
|
751
|
+
job = MarketIndexCapflowDC(
|
|
752
|
+
session=mock_session,
|
|
753
|
+
params={"start_date": "20240925", "end_date": "20240927"},
|
|
754
|
+
cache=False,
|
|
755
|
+
)
|
|
756
|
+
|
|
757
|
+
result = job.run()
|
|
758
|
+
|
|
759
|
+
assert len(result) == 3
|
|
760
|
+
# Verify dates are in ascending order
|
|
761
|
+
assert result.iloc[0]["date"] == "2024-09-25"
|
|
762
|
+
assert result.iloc[1]["date"] == "2024-09-26"
|
|
763
|
+
assert result.iloc[2]["date"] == "2024-09-27"
|
|
764
|
+
|
|
765
|
+
def test_negative_net_amount_handling(self, mock_session):
|
|
766
|
+
"""Test handling of negative net amounts (capital outflow)."""
|
|
767
|
+
mock_session.connection.moneyflow_mkt_dc.return_value = pd.DataFrame(
|
|
768
|
+
{
|
|
769
|
+
"trade_date": ["20240925"],
|
|
770
|
+
"close_sh": [2896.31],
|
|
771
|
+
"pct_change_sh": [1.16],
|
|
772
|
+
"close_sz": [8537.73],
|
|
773
|
+
"pct_change_sz": [1.21],
|
|
774
|
+
"net_amount": [-4010342144.00], # Negative - capital outflow
|
|
775
|
+
"net_amount_rate": [-3.5],
|
|
776
|
+
"buy_elg_amount": [-4010342144.00],
|
|
777
|
+
"buy_elg_amount_rate": [-2.0],
|
|
778
|
+
"buy_lg_amount": [-10390331392.00],
|
|
779
|
+
"buy_lg_amount_rate": [-5.2],
|
|
780
|
+
"buy_md_amount": [3456789012.00],
|
|
781
|
+
"buy_md_amount_rate": [2.5],
|
|
782
|
+
"buy_sm_amount": [-2345678901.00],
|
|
783
|
+
"buy_sm_amount_rate": [-1.5],
|
|
784
|
+
}
|
|
785
|
+
)
|
|
786
|
+
|
|
787
|
+
job = MarketIndexCapflowDC(session=mock_session, params={"trade_date": "20240925"}, cache=False)
|
|
788
|
+
|
|
789
|
+
result = job.run()
|
|
790
|
+
|
|
791
|
+
assert len(result) == 1
|
|
792
|
+
assert result.iloc[0]["net_amount"] < 0 # Capital outflow
|
|
793
|
+
assert result.iloc[0]["net_amount"] == pytest.approx(-4010342144.00)
|