quantvn 0.1.9__tar.gz → 0.1.10__tar.gz

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.
Files changed (36) hide show
  1. {quantvn-0.1.9/quantvn.egg-info → quantvn-0.1.10}/PKG-INFO +1 -1
  2. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/vn/data/stocks.py +62 -223
  3. {quantvn-0.1.9 → quantvn-0.1.10/quantvn.egg-info}/PKG-INFO +1 -1
  4. {quantvn-0.1.9 → quantvn-0.1.10}/setup.py +1 -1
  5. {quantvn-0.1.9 → quantvn-0.1.10}/LICENSE +0 -0
  6. {quantvn-0.1.9 → quantvn-0.1.10}/MANIFEST.in +0 -0
  7. {quantvn-0.1.9 → quantvn-0.1.10}/README.md +0 -0
  8. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/__init__.py +0 -0
  9. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/crypto/__init__.py +0 -0
  10. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/crypto/data/__init__.py +0 -0
  11. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/crypto/data/derivatives.py +0 -0
  12. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/crypto/data/download.py +0 -0
  13. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/crypto/metrics/__init__.py +0 -0
  14. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/crypto/metrics/backtest.py +0 -0
  15. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/crypto/metrics/metrics.py +0 -0
  16. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/metrics/__init__.py +0 -0
  17. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/metrics/portfolio.py +0 -0
  18. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/metrics/single_asset.py +0 -0
  19. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/metrics/st.py +0 -0
  20. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/paper/__init__.py +0 -0
  21. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/paper/portfolio.py +0 -0
  22. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/paper/single_asset.py +0 -0
  23. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/vn/__init__.py +0 -0
  24. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/vn/data/__init__.py +0 -0
  25. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/vn/data/const.py +0 -0
  26. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/vn/data/core.py +0 -0
  27. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/vn/data/derivatives.py +0 -0
  28. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/vn/data/utils.py +0 -0
  29. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/vn/metrics/__init__.py +0 -0
  30. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/vn/metrics/backtest.py +0 -0
  31. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn/vn/metrics/metrics.py +0 -0
  32. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn.egg-info/SOURCES.txt +0 -0
  33. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn.egg-info/dependency_links.txt +0 -0
  34. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn.egg-info/requires.txt +0 -0
  35. {quantvn-0.1.9 → quantvn-0.1.10}/quantvn.egg-info/top_level.txt +0 -0
  36. {quantvn-0.1.9 → quantvn-0.1.10}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quantvn
3
- Version: 0.1.9
3
+ Version: 0.1.10
4
4
  Summary: QuantVN API Library for Financial Data Analysis
5
5
  Author: quantvn
6
6
  Classifier: Development Status :: 3 - Alpha
@@ -1055,75 +1055,48 @@ class Company:
1055
1055
  return self._provider.ratio_summary()
1056
1056
 
1057
1057
 
1058
- FIN_MAP = {
1059
- "income_statement": "incomestatement",
1060
- "balance_sheet": "balancesheet",
1061
- "cash_flow": "cashflow",
1062
- }
1063
- PERIOD_MAP = {"year": 1, "quarter": 0}
1064
-
1065
-
1066
- # ===== VCI GraphQL Finance Queries =====
1067
- INCOME_STATEMENT_QUERY = """
1068
- query Query($ticker: String!, $period: Int!) {
1069
- IncomeStatement(ticker: $ticker, period: $period) {
1070
- id
1071
- ticker
1072
- year
1073
- quarter
1074
- revenue
1075
- costOfGoodsSold
1076
- grossProfit
1077
- operatingExpenses
1078
- operatingProfit
1079
- interestExpense
1080
- interestIncome
1081
- otherIncome
1082
- otherExpense
1083
- profitBeforeTax
1084
- incomeTaxExpense
1085
- netProfit
1086
- eps
1087
- __typename
1088
- }
1089
- }
1090
- """.strip()
1091
-
1092
- BALANCE_SHEET_QUERY = """
1093
- query Query($ticker: String!, $period: Int!) {
1094
- BalanceSheet(ticker: $ticker, period: $period) {
1095
- id
1096
- ticker
1097
- year
1098
- quarter
1099
- totalAssets
1100
- currentAssets
1101
- nonCurrentAssets
1102
- totalLiabilities
1103
- currentLiabilities
1104
- nonCurrentLiabilities
1105
- totalEquity
1106
- shareCapital
1107
- retainedEarnings
1108
- __typename
1109
- }
1058
+ # ===== VCI GraphQL Finance Ratio Query =====
1059
+ FINANCE_RATIO_QUERY = """
1060
+ fragment Ratios on CompanyFinancialRatio {
1061
+ ticker
1062
+ yearReport
1063
+ lengthReport
1064
+ updateDate
1065
+ revenue
1066
+ revenueGrowth
1067
+ netProfit
1068
+ netProfitGrowth
1069
+ ebitMargin
1070
+ roe
1071
+ roic
1072
+ roa
1073
+ pe
1074
+ pb
1075
+ eps
1076
+ currentRatio
1077
+ cashRatio
1078
+ quickRatio
1079
+ interestCoverage
1080
+ netProfitMargin
1081
+ grossMargin
1082
+ ev
1083
+ issueShare
1084
+ ps
1085
+ pcf
1086
+ bvps
1087
+ evPerEbitda
1088
+ charterCapital
1089
+ dividend
1090
+ ebitda
1091
+ ebit
1110
1092
  }
1111
- """.strip()
1112
1093
 
1113
- CASH_FLOW_QUERY = """
1114
- query Query($ticker: String!, $period: Int!) {
1115
- CashFlow(ticker: $ticker, period: $period) {
1116
- id
1117
- ticker
1118
- year
1119
- quarter
1120
- netCashFromOperating
1121
- netCashFromInvesting
1122
- netCashFromFinancing
1123
- netCashFlow
1124
- cashAtBeginning
1125
- cashAtEnd
1126
- __typename
1094
+ query Query($ticker: String!, $period: String!) {
1095
+ CompanyFinancialRatio(ticker: $ticker, period: $period) {
1096
+ ratio {
1097
+ ...Ratios
1098
+ }
1099
+ period
1127
1100
  }
1128
1101
  }
1129
1102
  """.strip()
@@ -1132,84 +1105,19 @@ query Query($ticker: String!, $period: Int!) {
1132
1105
  class _FinanceProvider:
1133
1106
  """Internal provider interface (do not use directly)."""
1134
1107
 
1135
- def income_statement(
1136
- self, period: str = "year", lang: str = "vi", dropna: bool = False
1137
- ) -> pd.DataFrame: # pragma: no cover
1138
- raise NotImplementedError
1139
-
1140
- def balance_sheet(
1141
- self, period: str = "year", lang: str = "vi", dropna: bool = False
1142
- ) -> pd.DataFrame: # pragma: no cover
1143
- raise NotImplementedError
1144
-
1145
- def cash_flow(
1146
- self, period: str = "year", lang: str = "vi", dropna: bool = False
1108
+ def ratio(
1109
+ self, period: str = "Q", dropna: bool = False
1147
1110
  ) -> pd.DataFrame: # pragma: no cover
1148
1111
  raise NotImplementedError
1149
1112
 
1150
1113
 
1151
1114
  class _VCIFinanceProvider(_FinanceProvider):
1152
- """Finance provider via VCI GraphQL API."""
1115
+ """Finance provider via VCI GraphQL API - only supports ratio()."""
1153
1116
 
1154
1117
  def __init__(self, symbol: str, *, lang: str = "vi"):
1155
1118
  self.symbol = str(symbol).upper().strip()
1156
1119
  self.lang = lang or "vi"
1157
- self._cache: Dict[str, Dict[str, Any]] = {}
1158
-
1159
- def _fetch_finance(self, query: str, report_type: str, period: str) -> pd.DataFrame:
1160
- """Fetch financial statement via GraphQL and return as DataFrame."""
1161
- period_val = PERIOD_MAP.get(period, 1)
1162
-
1163
- cache_key = f"{report_type}_{period}"
1164
- if cache_key not in self._cache:
1165
- try:
1166
- data = _vci_graphql_request(
1167
- query=query,
1168
- variables={"ticker": self.symbol, "period": period_val},
1169
- )
1170
- self._cache[cache_key] = data
1171
- except Exception as e:
1172
- raise ValueError(f"Failed to fetch {report_type} from VCI: {e}")
1173
-
1174
- data = self._cache[cache_key]
1175
- items = data.get(report_type) or []
1176
-
1177
- if not isinstance(items, list) or not items:
1178
- return pd.DataFrame()
1179
-
1180
- df = pd.DataFrame(items)
1181
- return df
1182
-
1183
- def income_statement(
1184
- self, period: str = "year", lang: str = "vi", dropna: bool = False
1185
- ) -> pd.DataFrame:
1186
- """Fetch income statement."""
1187
- df = self._fetch_finance(INCOME_STATEMENT_QUERY, "IncomeStatement", period)
1188
- if dropna and not df.empty:
1189
- df = df.dropna(axis=1, how="all")
1190
- return df
1191
-
1192
- def balance_sheet(
1193
- self, period: str = "year", lang: str = "vi", dropna: bool = False
1194
- ) -> pd.DataFrame:
1195
- """Fetch balance sheet."""
1196
- df = self._fetch_finance(BALANCE_SHEET_QUERY, "BalanceSheet", period)
1197
- if dropna and not df.empty:
1198
- df = df.dropna(axis=1, how="all")
1199
- return df
1200
1120
 
1201
- def cash_flow(
1202
- self, period: str = "year", lang: str = "vi", dropna: bool = False
1203
- ) -> pd.DataFrame:
1204
- """Fetch cash flow statement."""
1205
- df = self._fetch_finance(CASH_FLOW_QUERY, "CashFlow", period)
1206
- if dropna and not df.empty:
1207
- df = df.dropna(axis=1, how="all")
1208
- return df
1209
-
1210
- # ------------------------------------------------------------------
1211
- # Extra: Financial ratios from VCI (CompanyFinancialRatio)
1212
- # ------------------------------------------------------------------
1213
1121
  def ratio(self, period: str = "Q", dropna: bool = False) -> pd.DataFrame:
1214
1122
  """
1215
1123
  Fetch financial ratios from VCI CompanyFinancialRatio API.
@@ -1253,60 +1161,17 @@ class _VCIFinanceProvider(_FinanceProvider):
1253
1161
  return df
1254
1162
 
1255
1163
 
1256
- class _TCBSFinanceProvider(_FinanceProvider):
1257
- """Finance provider via TCBS tcanalysis endpoints (kept as fallback)."""
1258
-
1259
- def __init__(self, symbol: str):
1260
- self.symbol = str(symbol).upper().strip()
1261
-
1262
- def _fetch(
1263
- self, report: str, period: str = "year", lang: str = "vi", dropna: bool = False
1264
- ) -> pd.DataFrame:
1265
- BASE = "https://apipubaws.tcbs.com.vn"
1266
- ANALYSIS = "tcanalysis"
1267
- assert report in FIN_MAP, f"Invalid report: {report}"
1268
- url = f"{BASE}/{ANALYSIS}/v1/finance/{self.symbol}/{FIN_MAP[report]}"
1269
- params = {"period": PERIOD_MAP.get(period, 1), "size": 1000}
1270
- data = send_request(url, params=params)
1271
- df = pd.DataFrame(data)
1272
- if dropna:
1273
- df = df.dropna(axis=1, how="all")
1274
- return df
1275
-
1276
- def income_statement(
1277
- self, period: str = "year", lang: str = "vi", dropna: bool = False
1278
- ) -> pd.DataFrame:
1279
- return self._fetch("income_statement", period, lang, dropna)
1280
-
1281
- def balance_sheet(
1282
- self, period: str = "year", lang: str = "vi", dropna: bool = False
1283
- ) -> pd.DataFrame:
1284
- return self._fetch("balance_sheet", period, lang, dropna)
1285
-
1286
- def cash_flow(
1287
- self, period: str = "year", lang: str = "vi", dropna: bool = False
1288
- ) -> pd.DataFrame:
1289
- return self._fetch("cash_flow", period, lang, dropna)
1290
-
1291
- def ratio(self, period: str = "Q", dropna: bool = False) -> pd.DataFrame:
1292
- """
1293
- TCBS currently does not expose the same CompanyFinancialRatio GraphQL;
1294
- keep a simple stub that returns empty DataFrame for symmetry.
1295
- """
1296
- return pd.DataFrame()
1297
-
1298
-
1299
1164
  class Finance:
1300
1165
  """
1301
- Public Finance API (stable surface).
1166
+ Public Finance API - Tỷ số tài chính từ VCI GraphQL API.
1302
1167
 
1303
- Only exposes:
1304
- - income_statement(period="year", lang="vi", dropna=False)
1305
- - balance_sheet(period="year", lang="vi", dropna=False)
1306
- - cash_flow(period="year", lang="vi", dropna=False)
1307
- - ratio(period="Q" | "Y", dropna=False) # via VCI CompanyFinancialRatio
1168
+ Chỉ hỗ trợ:
1169
+ - ratio(period="Q" | "Y", dropna=False) # Tỷ số tài chính từ VCI CompanyFinancialRatio
1308
1170
 
1309
- Internally uses a provider so you can swap/add APIs later easily.
1171
+ Args:
1172
+ symbol: Mã cổ phiếu (VD: "HPG", "VIC")
1173
+ source: Nguồn dữ liệu (chỉ hỗ trợ "VCI")
1174
+ lang: Ngôn ngữ (mặc định "vi")
1310
1175
  """
1311
1176
 
1312
1177
  def __init__(self, symbol: str, source: str = "VCI", lang: str = "vi"):
@@ -1314,51 +1179,25 @@ class Finance:
1314
1179
  self.source = (source or "VCI").upper()
1315
1180
  self.lang = lang or "vi"
1316
1181
 
1317
- if self.source == "VCI":
1318
- self._provider: _FinanceProvider = _VCIFinanceProvider(
1319
- self.symbol, lang=self.lang
1320
- )
1321
- elif self.source == "TCBS":
1322
- self._provider = _TCBSFinanceProvider(self.symbol)
1323
- elif self.source == "AUTO":
1324
- # Try VCI first; if it fails, fallback to TCBS.
1325
- try:
1326
- self._provider = _VCIFinanceProvider(self.symbol, lang=self.lang)
1327
- _ = self._provider.income_statement()
1328
- except Exception:
1329
- self._provider = _TCBSFinanceProvider(self.symbol)
1330
- else:
1331
- raise ValueError("source must be one of: 'VCI', 'TCBS', 'AUTO'")
1332
-
1333
- def income_statement(
1334
- self, period: str = "year", lang: str = "vi", dropna: bool = False
1335
- ) -> pd.DataFrame:
1336
- return self._provider.income_statement(period=period, lang=lang, dropna=dropna)
1337
-
1338
- def balance_sheet(
1339
- self, period: str = "year", lang: str = "vi", dropna: bool = False
1340
- ) -> pd.DataFrame:
1341
- return self._provider.balance_sheet(period=period, lang=lang, dropna=dropna)
1182
+ if self.source != "VCI":
1183
+ raise ValueError("Finance class chỉ hỗ trợ source='VCI' (VCI GraphQL API)")
1342
1184
 
1343
- def cash_flow(
1344
- self, period: str = "year", lang: str = "vi", dropna: bool = False
1345
- ) -> pd.DataFrame:
1346
- return self._provider.cash_flow(period=period, lang=lang, dropna=dropna)
1185
+ self._provider: _FinanceProvider = _VCIFinanceProvider(
1186
+ self.symbol, lang=self.lang
1187
+ )
1347
1188
 
1348
1189
  def ratio(self, period: str = "Q", dropna: bool = False) -> pd.DataFrame:
1349
1190
  """
1350
- Financial ratios from VCI CompanyFinancialRatio endpoint.
1191
+ Tỷ số tài chính từ VCI CompanyFinancialRatio endpoint.
1351
1192
 
1352
1193
  Args:
1353
- period: "Q" (quarterly) or "Y" (yearly), matching the working test script.
1194
+ period: "Q" (quý) hoặc "Y" (năm)
1195
+ dropna: Xóa các cột hoàn toàn trống
1196
+
1197
+ Returns:
1198
+ DataFrame chứa các tỷ số tài chính như revenue, netProfit, roe, pe, pb, etc.
1354
1199
  """
1355
- # Always go through VCI provider for ratios (this is what the user-tested script uses)
1356
- vci_provider: _VCIFinanceProvider
1357
- if isinstance(self._provider, _VCIFinanceProvider):
1358
- vci_provider = self._provider
1359
- else:
1360
- vci_provider = _VCIFinanceProvider(self.symbol, lang=self.lang)
1361
- return vci_provider.ratio(period=period, dropna=dropna)
1200
+ return self._provider.ratio(period=period, dropna=dropna)
1362
1201
 
1363
1202
 
1364
1203
  # ===================== Reorganized: Fund =====================
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quantvn
3
- Version: 0.1.9
3
+ Version: 0.1.10
4
4
  Summary: QuantVN API Library for Financial Data Analysis
5
5
  Author: quantvn
6
6
  Classifier: Development Status :: 3 - Alpha
@@ -2,7 +2,7 @@ from setuptools import find_packages, setup
2
2
 
3
3
  setup(
4
4
  name="quantvn",
5
- version="0.1.9",
5
+ version="0.1.10",
6
6
  packages=find_packages(),
7
7
  install_requires=[
8
8
  "requests",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes