oxtapus 0.4.1__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.
- oxtapus/__init__.py +6 -0
- oxtapus/fipiran.py +36 -0
- oxtapus/models/__init__.py +0 -0
- oxtapus/models/fipiran.py +55 -0
- oxtapus/models/rahavard.py +109 -0
- oxtapus/models/tsetmc.py +165 -0
- oxtapus/rahavard.py +357 -0
- oxtapus/tgju.py +192 -0
- oxtapus/tsetmc.py +1770 -0
- oxtapus/utils/__init__.py +6 -0
- oxtapus/utils/columns.py +228 -0
- oxtapus/utils/http/__init__.py +1 -0
- oxtapus/utils/http/requests.py +59 -0
- oxtapus/utils/models.py +72 -0
- oxtapus/utils/normalize.py +25 -0
- oxtapus-0.4.1.dist-info/METADATA +328 -0
- oxtapus-0.4.1.dist-info/RECORD +20 -0
- oxtapus-0.4.1.dist-info/WHEEL +5 -0
- oxtapus-0.4.1.dist-info/licenses/LICENSE.txt +21 -0
- oxtapus-0.4.1.dist-info/top_level.txt +1 -0
oxtapus/__init__.py
ADDED
oxtapus/fipiran.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import polars as pl
|
|
2
|
+
|
|
3
|
+
from oxtapus.models.fipiran import DependencyGraph
|
|
4
|
+
from oxtapus.utils.http import get
|
|
5
|
+
from oxtapus.utils.normalize import normalize_nested_dict
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Fipiran:
|
|
9
|
+
def __init__(self) -> None:
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
def funds(self) -> pl.DataFrame:
|
|
13
|
+
"""
|
|
14
|
+
.. raw:: html
|
|
15
|
+
|
|
16
|
+
<div dir="rtl">
|
|
17
|
+
ی سری دادهیِ از صندوقهایِ سرمایه-گذاری رو بهت میده.
|
|
18
|
+
</div>
|
|
19
|
+
"""
|
|
20
|
+
url = "https://fund.fipiran.ir/api/v1/fund/dependencygraph"
|
|
21
|
+
r = get(url)
|
|
22
|
+
items = list(filter(lambda x: self._is_gt(x["netAsset"], 0.0), r[0]["items"]))
|
|
23
|
+
validated_r = DependencyGraph.model_validate({"items": items})
|
|
24
|
+
norm_r = normalize_nested_dict(
|
|
25
|
+
[i.model_dump() for i in validated_r.items], "manager"
|
|
26
|
+
)
|
|
27
|
+
return pl.DataFrame(norm_r)
|
|
28
|
+
|
|
29
|
+
def _is_gt(self, x, t: float) -> bool:
|
|
30
|
+
try:
|
|
31
|
+
number = float(x)
|
|
32
|
+
if number > t:
|
|
33
|
+
return True
|
|
34
|
+
return False
|
|
35
|
+
except Exception:
|
|
36
|
+
return False
|
|
File without changes
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import datetime as dt
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, Field, field_validator
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Manager(BaseModel):
|
|
8
|
+
address: Optional[str]
|
|
9
|
+
ceo: Optional[str]
|
|
10
|
+
cfi_id: Optional[int] = Field(alias="cfiId")
|
|
11
|
+
cfiLast_modification_datetime: Optional[str] = Field(
|
|
12
|
+
alias="cfiLastModificationTime"
|
|
13
|
+
)
|
|
14
|
+
is_completed: bool = Field(alias="isCompleted")
|
|
15
|
+
manager_id: Optional[int] = Field(alias="managerId")
|
|
16
|
+
manager_national_no: Optional[str] = Field(alias="managerNationalCode")
|
|
17
|
+
manager_seo_register_no: Optional[str] = Field(alias="managerSeoRegisterNo")
|
|
18
|
+
name: Optional[str]
|
|
19
|
+
national_id: Optional[str] = Field(alias="nationalId")
|
|
20
|
+
register_date: Optional[str] = Field(alias="registerDate")
|
|
21
|
+
register_place: Optional[str] = Field(alias="registerPlace")
|
|
22
|
+
register_place_id: Optional[str] = Field(alias="registerPlaceId")
|
|
23
|
+
registered_capital: Optional[int] = Field(alias="registeredCapital")
|
|
24
|
+
registration_number: Optional[str] = Field(alias="registrationNumber")
|
|
25
|
+
seoRegisterDate: Optional[str] = Field("seo_register_date")
|
|
26
|
+
tel: Optional[str]
|
|
27
|
+
type: Optional[int]
|
|
28
|
+
web_site: Optional[str] = Field(alias="webSite")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class FundItem(BaseModel):
|
|
32
|
+
date: dt.date
|
|
33
|
+
initiation_date: dt.date = Field(alias="initiationDate")
|
|
34
|
+
name: str
|
|
35
|
+
temp_guarantor_name: Optional[str] = Field(alias="tempGuarantorName")
|
|
36
|
+
temp_manager_name: str = Field(alias="tempManagerName")
|
|
37
|
+
type_of_invest: str = Field(alias="typeOfInvest")
|
|
38
|
+
fund_type: int = Field(alias="fundType")
|
|
39
|
+
manager: Manager
|
|
40
|
+
dividend_interval_period: Optional[int] = Field(alias="dividendIntervalPeriod")
|
|
41
|
+
# guarantor: Optional[str]
|
|
42
|
+
fund_size: Optional[int] = Field(alias="fundSize")
|
|
43
|
+
net_asset: Optional[int] = Field(alias="netAsset")
|
|
44
|
+
reg_no: str = Field(alias="regNo")
|
|
45
|
+
issue_nav: Optional[int] = Field(alias="issueNav")
|
|
46
|
+
statistical_nav: Optional[int] = Field(alias="statisticalNav")
|
|
47
|
+
cancel_nav: Optional[int] = Field(alias="cancelNav")
|
|
48
|
+
|
|
49
|
+
@field_validator("date", mode="before")
|
|
50
|
+
def parse_date(cls, value):
|
|
51
|
+
return dt.datetime.fromisoformat(str(value)).date()
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class DependencyGraph(BaseModel):
|
|
55
|
+
items: list[FundItem]
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import datetime as dt
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, field_validator
|
|
5
|
+
|
|
6
|
+
__all__ = ["Stocks", "BalanceSheet", "IncomeStatements", "CashFlow"]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class FSField(BaseModel):
|
|
10
|
+
title: str
|
|
11
|
+
english_title: str
|
|
12
|
+
account: Optional[str] = "-"
|
|
13
|
+
is_parent: bool
|
|
14
|
+
parent: Optional[str]
|
|
15
|
+
index_view: int
|
|
16
|
+
id: str
|
|
17
|
+
sign_neg: bool
|
|
18
|
+
sign_pos: bool
|
|
19
|
+
neg_nature: bool
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class FSItems(BaseModel):
|
|
23
|
+
field: FSField
|
|
24
|
+
value: float
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class FinancialViewType(BaseModel):
|
|
28
|
+
id: str
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class BalanceSheetData(BaseModel):
|
|
32
|
+
date: dt.date
|
|
33
|
+
fiscal_year: dt.date
|
|
34
|
+
announcement_type: str
|
|
35
|
+
financial_view_type: FinancialViewType
|
|
36
|
+
report_id: str
|
|
37
|
+
id: str
|
|
38
|
+
items: list[FSItems]
|
|
39
|
+
|
|
40
|
+
@field_validator("date", "fiscal_year", mode="before")
|
|
41
|
+
def parse_date(cls, value):
|
|
42
|
+
return dt.datetime.strptime(
|
|
43
|
+
str(value),
|
|
44
|
+
"%Y-%m-%dT%H:%M:%S%z",
|
|
45
|
+
).date()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class BalanceSheet(BaseModel):
|
|
49
|
+
data: list[BalanceSheetData]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class IncomeStatementsData(BaseModel):
|
|
53
|
+
date: dt.date
|
|
54
|
+
fiscal_year: dt.date
|
|
55
|
+
announcement_type_id: str
|
|
56
|
+
financial_view_type_id: str
|
|
57
|
+
report_id: str
|
|
58
|
+
capital: int
|
|
59
|
+
id: str
|
|
60
|
+
items: list[FSItems]
|
|
61
|
+
|
|
62
|
+
@field_validator("date", "fiscal_year", mode="before")
|
|
63
|
+
def parse_date(cls, value):
|
|
64
|
+
return dt.datetime.strptime(
|
|
65
|
+
str(value),
|
|
66
|
+
"%Y-%m-%dT%H:%M:%S%z",
|
|
67
|
+
).date()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class IncomeStatements(BaseModel):
|
|
71
|
+
data: list[IncomeStatementsData]
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class CashFlowField(BaseModel):
|
|
75
|
+
title: str
|
|
76
|
+
english_title: str
|
|
77
|
+
account: Optional[str] = "-"
|
|
78
|
+
is_parent: bool
|
|
79
|
+
index_view: int
|
|
80
|
+
id: str
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class CashFlowItems(BaseModel):
|
|
84
|
+
field: CashFlowField
|
|
85
|
+
value: float
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class CashFlowData(BaseModel):
|
|
89
|
+
date: dt.date
|
|
90
|
+
fiscal_year: dt.date
|
|
91
|
+
announcement_type_id: str
|
|
92
|
+
financial_view_type_id: str
|
|
93
|
+
report_id: str
|
|
94
|
+
id: str
|
|
95
|
+
items: list[CashFlowItems]
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class CashFlow(BaseModel):
|
|
99
|
+
data: list[CashFlowData]
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class StocksData(BaseModel):
|
|
103
|
+
name: str
|
|
104
|
+
asset_id: str
|
|
105
|
+
exchange_id: str
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class Stocks(BaseModel):
|
|
109
|
+
data: list[StocksData]
|
oxtapus/models/tsetmc.py
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import datetime as dt
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, Field, field_validator, model_validator
|
|
5
|
+
from pydantic.v1.utils import GetterDict
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class MarketWatchOrderBook(BaseModel):
|
|
9
|
+
ob_level: int = Field(alias="n")
|
|
10
|
+
bid_count: int = Field(alias="zmd")
|
|
11
|
+
bid_size: float = Field(alias="qmd")
|
|
12
|
+
bid_price: float = Field(alias="pmd")
|
|
13
|
+
ask_price: float = Field(alias="pmo")
|
|
14
|
+
ask_size: float = Field(alias="qmo")
|
|
15
|
+
ask_count: int = Field(alias="zmo")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ClientTypeAll(BaseModel):
|
|
19
|
+
ins_code: str = Field(alias="insCode")
|
|
20
|
+
buy_vol_ind: float = Field(alias="buy_I_Volume")
|
|
21
|
+
buy_vol_ins: float = Field(alias="buy_N_Volume")
|
|
22
|
+
buy_count_ind: int = Field(alias="buy_CountI")
|
|
23
|
+
buy_count_ins: int = Field(alias="buy_CountN")
|
|
24
|
+
sell_vol_ind: float = Field(alias="sell_I_Volume")
|
|
25
|
+
sell_vol_ins: float = Field(alias="sell_N_Volume")
|
|
26
|
+
sell_count_ind: int = Field(alias="sell_CountI")
|
|
27
|
+
sell_count_ins: int = Field(alias="sell_CountN")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class MarketWatch(BaseModel):
|
|
31
|
+
ins_code: str = Field(alias="insCode")
|
|
32
|
+
ins_id: str = Field(alias="insID")
|
|
33
|
+
symbol: str = Field(alias="lva")
|
|
34
|
+
name: str = Field(alias="lvc")
|
|
35
|
+
eps: float = Field(alias="eps")
|
|
36
|
+
pe: float = Field(alias="pe")
|
|
37
|
+
bid: float = Field(alias="pmd") #
|
|
38
|
+
ask: float = Field(alias="pmo") #
|
|
39
|
+
open: float = Field(alias="pf")
|
|
40
|
+
high: float = Field(alias="pmx")
|
|
41
|
+
low: float = Field(alias="pmn")
|
|
42
|
+
close: float = Field(alias="pdv")
|
|
43
|
+
final: float = Field(alias="pcl")
|
|
44
|
+
y_final: float = Field(alias="py")
|
|
45
|
+
value: float = Field(alias="qtc")
|
|
46
|
+
volume: float = Field(alias="qtj")
|
|
47
|
+
trade_count: float = Field(alias="ztt")
|
|
48
|
+
max_lim: float = Field(alias="pMax")
|
|
49
|
+
min_lim: float = Field(alias="pMin")
|
|
50
|
+
capital: float = Field(alias="ztd")
|
|
51
|
+
base_volume: float = Field(alias="bv")
|
|
52
|
+
event_time: float = Field(alias="hEven")
|
|
53
|
+
order_book: list[MarketWatchOrderBook] = Field(alias="blDs")
|
|
54
|
+
|
|
55
|
+
@field_validator("pe", mode="before")
|
|
56
|
+
def parce_pe(cls, value):
|
|
57
|
+
try:
|
|
58
|
+
return float(value)
|
|
59
|
+
except ValueError:
|
|
60
|
+
return 0.0
|
|
61
|
+
except TypeError:
|
|
62
|
+
return 0.0
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class HistPrice(BaseModel):
|
|
66
|
+
date: dt.date = Field(alias="dEven")
|
|
67
|
+
ins_code: str = Field(alias="insCode")
|
|
68
|
+
open: float = Field(alias="priceFirst")
|
|
69
|
+
high: float = Field(alias="priceMax")
|
|
70
|
+
low: float = Field(alias="priceMin")
|
|
71
|
+
close: float = Field(alias="pDrCotVal")
|
|
72
|
+
final: float = Field(alias="pClosing")
|
|
73
|
+
y_final: float = Field(alias="priceYesterday")
|
|
74
|
+
volume: float = Field(alias="qTotTran5J")
|
|
75
|
+
value: float = Field(alias="qTotCap")
|
|
76
|
+
trade_count: float = Field(alias="zTotTran")
|
|
77
|
+
|
|
78
|
+
@field_validator("date", mode="before")
|
|
79
|
+
def parse_date(cls, value):
|
|
80
|
+
return dt.datetime.strptime(str(value), "%Y%m%d").date()
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class EPS(BaseModel):
|
|
84
|
+
eps: Optional[float] = Field(alias="estimatedEPS")
|
|
85
|
+
sector_pe: Optional[float] = Field(alias="sectorPE")
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class Sector(BaseModel):
|
|
89
|
+
code: str = Field(alias="cSecVal")
|
|
90
|
+
name: str = Field(alias="lSecVal")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class StaticThreshold(BaseModel):
|
|
94
|
+
min_threshold: float = Field(alias="psGelStaMin")
|
|
95
|
+
max_threshold: float = Field(alias="psGelStaMax")
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class InsInfo(BaseModel):
|
|
99
|
+
ins_code: str = Field(alias="insCode")
|
|
100
|
+
ins_id: str = Field(alias="instrumentID")
|
|
101
|
+
isin: str = Field(alias="cIsin")
|
|
102
|
+
symbol: str = Field(alias="lVal18AFC")
|
|
103
|
+
name: str = Field(alias="lVal30")
|
|
104
|
+
name_en: str = Field(alias="lVal18")
|
|
105
|
+
eps: Optional[float]
|
|
106
|
+
sector_pe: Optional[float]
|
|
107
|
+
static_threshold: StaticThreshold = Field(alias="staticThreshold")
|
|
108
|
+
min_week: float = Field(alias="minWeek")
|
|
109
|
+
max_week: float = Field(alias="maxWeek")
|
|
110
|
+
min_year: float = Field(alias="minYear")
|
|
111
|
+
max_year: float = Field(alias="maxYear")
|
|
112
|
+
mean_vol_monthly: float = Field(alias="qTotTran5JAvg")
|
|
113
|
+
pct_float_shares: Optional[str] = Field(alias="kAjCapValCpsIdx")
|
|
114
|
+
base_vol: int = Field(alias="baseVol")
|
|
115
|
+
capital: float = Field(alias="zTitad")
|
|
116
|
+
contract_size: float = Field(alias="contractSize")
|
|
117
|
+
sector_code: str
|
|
118
|
+
sector_name: str
|
|
119
|
+
market_name: str = Field(alias="flowTitle")
|
|
120
|
+
market_code: int = Field(alias="flow")
|
|
121
|
+
market_type: str = Field(alias="cgrValCotTitle")
|
|
122
|
+
group_type: str = Field(alias="cgrValCot")
|
|
123
|
+
|
|
124
|
+
@model_validator(mode="before")
|
|
125
|
+
def flatten_eps_sector(cls, values: GetterDict):
|
|
126
|
+
eps = values.get("eps")
|
|
127
|
+
sector = values.get("sector")
|
|
128
|
+
eps = EPS.model_validate(eps)
|
|
129
|
+
sector = Sector.model_validate(sector)
|
|
130
|
+
|
|
131
|
+
result = {
|
|
132
|
+
"eps": eps.eps,
|
|
133
|
+
"sector_pe": eps.sector_pe,
|
|
134
|
+
"sector_code": sector.code,
|
|
135
|
+
"sector_name": sector.name,
|
|
136
|
+
}
|
|
137
|
+
values.pop("eps")
|
|
138
|
+
values.pop("sector")
|
|
139
|
+
result.update(values)
|
|
140
|
+
return result
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class SubSector(BaseModel):
|
|
144
|
+
id: int = Field(alias="cSoSecVal")
|
|
145
|
+
name: str = Field(alias="lSoSecVal")
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class InstrumentIdentity(BaseModel):
|
|
149
|
+
isin: str = Field(alias="cIsin")
|
|
150
|
+
instrument_id: str = Field(alias="instrumentID")
|
|
151
|
+
name: str = Field(alias="lSoc30")
|
|
152
|
+
symbol: str = Field(alias="lVal18AFC")
|
|
153
|
+
symbol30: str = Field(alias="lVal30")
|
|
154
|
+
sector: Sector
|
|
155
|
+
sub_sector: SubSector = Field(alias="subSector")
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class OrderBook(BaseModel):
|
|
159
|
+
ob_level: int = Field(alias="number")
|
|
160
|
+
bid_count: int = Field(alias="zOrdMeDem")
|
|
161
|
+
bid_volume: float = Field(alias="qTitMeDem")
|
|
162
|
+
bid_price: float = Field(alias="pMeDem")
|
|
163
|
+
ask_price: float = Field(alias="pMeOf")
|
|
164
|
+
ask_volume: float = Field(alias="qTitMeOf")
|
|
165
|
+
ask_count: int = Field(alias="zOrdMeOf")
|