oxtapus 0.2.2__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/.DS_Store ADDED
Binary file
oxtapus/__init__.py ADDED
File without changes
@@ -0,0 +1 @@
1
+ from .tgju import TGJU
oxtapus/econ/tgju.py ADDED
@@ -0,0 +1,58 @@
1
+ import pandas as pd
2
+ from ..utils import get
3
+
4
+
5
+ class TGJU:
6
+ """
7
+ دریافتِ داده‌هایِ گذشته‌یِ سایتِ www.econ.org
8
+ """
9
+
10
+ def __init__(self):
11
+ pass
12
+
13
+ @staticmethod
14
+ def get_hist_price(item):
15
+ url = f"https://api.tgju.org/v1/market/indicator/summary-table-data/{item}"
16
+ main = get(url=url, timeout=(2, 6), verify=True).json()
17
+ df = pd.DataFrame().from_records(main["data"]).drop([4, 5], axis=1)
18
+ df.columns = ["open", "low", "high", "close", "date", "jdate"]
19
+ df[["open", "low", "high", "close"]] = df[
20
+ ["open", "low", "high", "close"]
21
+ ].applymap(lambda x: float(x.replace(",", "")))
22
+ df["date"] = pd.to_datetime(df.date)
23
+ return df.set_index("date").sort_index()
24
+
25
+ def usd_irr(self):
26
+ """
27
+ دلار/ریال
28
+ :return:
29
+ """
30
+ return self.get_hist_price("price_dollar_rl")
31
+
32
+ def sekke_emami(self):
33
+ """
34
+ سکه‌یِ امامی
35
+ :return:
36
+ """
37
+ return self.get_hist_price("sekee")
38
+
39
+ def nim_sekke(self):
40
+ """
41
+ نیم-سکه
42
+ :return:
43
+ """
44
+ return self.get_hist_price("nim")
45
+
46
+ def rob_sekke(self):
47
+ """
48
+ ربعِ-سکه
49
+ :return:
50
+ """
51
+ return self.get_hist_price("rob")
52
+
53
+ def ons(self):
54
+ """
55
+ اونس طلا
56
+ :return:
57
+ """
58
+ return self.get_hist_price("ons")
@@ -0,0 +1,3 @@
1
+ from .tsetmc import TSETMC
2
+ from .rahavard import Rahavard
3
+ from .codal import Codal
oxtapus/ise/codal.py ADDED
@@ -0,0 +1,86 @@
1
+ import pandas as pd
2
+
3
+ from .codal_utils import URL, QueryParameters, ced, cols
4
+ from ..utils import get
5
+
6
+
7
+ class Codal(URL):
8
+ def __init__(self, **kwargs):
9
+ super().__init__(**kwargs)
10
+
11
+ def letters(self):
12
+ main = get(self.search_url, verify=True, timeout=(2, 7)).json()
13
+ df = pd.DataFrame(main.get("Letters")).rename(columns=cols.letters.rename)[
14
+ cols.letters.rep
15
+ ]
16
+ page = main.get("Page")
17
+ if page > 1:
18
+ for i in range(1, page + 1):
19
+ self.page_number = i
20
+ main_ = get(self.search_url).json()
21
+ df_ = pd.DataFrame(main_.get("Letters")).rename(
22
+ columns=cols.letters.rename
23
+ )[cols.letters.rep]
24
+ df = pd.concat([df, df_])
25
+ df.replace({"\u200c": " "}, regex=True)
26
+ return df
27
+
28
+ def income_statements(self):
29
+ letters = self.letters()
30
+ df = pd.DataFrame()
31
+ for i, row in letters.iterrows():
32
+ url = self.financial_statements(letter_url=row.url, sheet_id=1)
33
+ try:
34
+ r = get(url, verify=True, timeout=(2, 10))
35
+ df_ = ced.income_statements(r.text)
36
+ df_ = df_.join(
37
+ pd.DataFrame.from_dict(
38
+ [
39
+ row[
40
+ [
41
+ "symbol",
42
+ "company_name",
43
+ "title",
44
+ "issue_datetime",
45
+ "url",
46
+ ]
47
+ ].to_dict()
48
+ ]
49
+ )
50
+ )
51
+ df = pd.concat([df, df_])
52
+ except Exception as e:
53
+ print(e)
54
+ print(url)
55
+
56
+ return df[cols.income_statements.rep]
57
+
58
+ def balance_sheet(self):
59
+ letters = self.letters()
60
+ df = pd.DataFrame()
61
+ for i, row in letters.iterrows():
62
+ url = self.financial_statements(letter_url=row.url, sheet_id=0)
63
+ try:
64
+ r = get(url, verify=True, timeout=(2, 10))
65
+ df_ = ced.balance_sheet(r.text)
66
+ df_ = df_.join(
67
+ pd.DataFrame.from_dict(
68
+ [
69
+ row[
70
+ [
71
+ "symbol",
72
+ "company_name",
73
+ "title",
74
+ "issue_datetime",
75
+ "url",
76
+ ]
77
+ ].to_dict()
78
+ ]
79
+ )
80
+ )
81
+ df = pd.concat([df, df_])
82
+ except Exception as e:
83
+ print(e)
84
+ print(url)
85
+ return df[cols.balance_sheet.rep]
86
+
@@ -0,0 +1,3 @@
1
+ from .columns import cols
2
+ from .constants import URL, QueryParameters
3
+ from .clean_and_extend_data import ced
@@ -0,0 +1,127 @@
1
+ from collections import namedtuple
2
+ import re
3
+ import json
4
+ import pandas as pd
5
+ from hazm import Normalizer
6
+
7
+ from .columns import cols
8
+ from .fs_items import fs_items
9
+
10
+ normalizer = Normalizer()
11
+ Ced = namedtuple("Ced", ["letters", "balance_sheet", "income_statements", "cash_flows"])
12
+
13
+
14
+ # ------------- ****** -------------
15
+ def codal_parser(text):
16
+ t = text.split("var datasource =")[1].split("};")[0].strip() + "}"
17
+ return json.loads(t)
18
+
19
+
20
+ def arabic_char(s: str):
21
+ return s.translate(str.maketrans({"ي": "ی", "ك": "ک"}))
22
+
23
+
24
+ def match_date(t):
25
+ t = t.replace("/", "-")
26
+ try:
27
+ return re.findall("\d{1,4}-\d{1,2}-\d{2,4}", t)[0]
28
+ except:
29
+ print(("enter valid text to match date"))
30
+
31
+
32
+ # ------------- letters -------------
33
+ def letters(url):
34
+ pass
35
+
36
+
37
+ # ------------- balance_sheet -------------
38
+ def clean_balance_sheet(df):
39
+ df.item = (
40
+ df.item.fillna("").map(normalizer.normalize).map(fs_items.balance_sheet)
41
+ )
42
+ df.dropna(inplace=True)
43
+ df.iloc[:, 1] = pd.to_numeric(df.iloc[:, 1], errors="raise")
44
+ df.dropna(inplace=True)
45
+ df.drop_duplicates(inplace=True)
46
+ df = df.groupby("item").sum().reset_index()
47
+ df = (
48
+ df.pivot_table(columns=["item"], aggfunc=sum)
49
+ .reset_index()
50
+ .rename(columns={"index": "period_end_to_date"})
51
+ )
52
+ df.columns.set_names(None, inplace=True)
53
+ return df
54
+
55
+
56
+ def balance_sheet(r):
57
+ dict_ = codal_parser(r)
58
+ records = dict_["sheets"][0]["tables"][0]["cells"]
59
+ try:
60
+ if dict_["sheets"][0]["tables"][1]["aliasName"] == "BalanceSheet":
61
+ records = dict_["sheets"][0]["tables"][1]["cells"]
62
+ except :
63
+ records = dict_["sheets"][0]["tables"][0]["cells"]
64
+ cols_ = ["item", dict_["periodEndToDate"]]
65
+ df = pd.DataFrame()
66
+ for i in records:
67
+ df.loc[i.get("rowSequence"), i.get("columnCode")] = i.get("value")
68
+ len_cols = len(df.columns)
69
+ df.sort_index(inplace=True)
70
+ if len_cols > 7:
71
+ df_right = df.iloc[:, :2]
72
+ df_right.columns = cols_
73
+ df_left = df.iloc[:, int(len_cols / 2):int(len_cols / 2 + 2)]
74
+ df_left.columns = cols_
75
+ df = pd.concat([df_right, df_left])
76
+ return clean_balance_sheet(df)
77
+ else:
78
+ df = df.iloc[:, :2]
79
+ df.columns = cols_
80
+ return clean_balance_sheet(df)
81
+
82
+
83
+ # ------------- income_statements -------------
84
+
85
+
86
+ def clean_income_statements(df):
87
+ df = df[[1, 2]]
88
+ df.columns = ["item", match_date(df[df[1] == "شرح"][2].values[0])]
89
+ df.item = (
90
+ df.item.fillna("").map(normalizer.normalize).map(fs_items.income_statements)
91
+ )
92
+ df.dropna(inplace=True)
93
+ df.iloc[:, 1] = pd.to_numeric(df.iloc[:, 1], errors="raise")
94
+ df.dropna(inplace=True)
95
+ df.drop_duplicates(inplace=True)
96
+ df = df.groupby("item").sum().reset_index()
97
+ df = (
98
+ df.pivot_table(columns=["item"], aggfunc=sum)
99
+ .reset_index()
100
+ .rename(columns={"index": "period_end_to_date"})
101
+ )
102
+ df.columns.set_names(None, inplace=True)
103
+ return df
104
+
105
+
106
+ def income_statements(r: str):
107
+ dict_ = codal_parser(r)
108
+ records = dict_["sheets"][0]["tables"][0]["cells"]
109
+ if dict_["sheets"][0]["tables"][1]["aliasName"] == "IncomeStatement":
110
+ records = dict_["sheets"][0]["tables"][1]["cells"]
111
+ df = pd.DataFrame()
112
+ for i in records:
113
+ df.loc[i.get("rowCode"), i.get("columnCode")] = i.get("value")
114
+ return clean_income_statements(df.sort_index())
115
+
116
+
117
+ # ------------- cash_flows -------------
118
+ def cash_flows():
119
+ pass
120
+
121
+
122
+ ced = Ced(
123
+ letters=letters,
124
+ balance_sheet=balance_sheet,
125
+ income_statements=income_statements,
126
+ cash_flows=cash_flows,
127
+ )
@@ -0,0 +1,128 @@
1
+ from collections import namedtuple
2
+
3
+ Cols = namedtuple("Cols", ["letters", "income_statements", "balance_sheet"])
4
+ Property = namedtuple("Property", ["rename", "drop", "rep"])
5
+
6
+ _letters = {
7
+ "rename": {
8
+ "Symbol": "symbol",
9
+ "CompanyName": "company_name",
10
+ "Title": "title",
11
+ "SentDateTime": "sent_datetime",
12
+ "PublishDateTime": "issue_datetime",
13
+ "HasAttachment": "has_attachment",
14
+ "HasPdf": "has_pdf",
15
+ "Url": "url",
16
+ "AttachmentUrl": "attachment_url",
17
+ "PdfUrl": "pdf_url",
18
+ "ExcelUrl": "excel_url",
19
+ },
20
+ "rep": [
21
+ "symbol",
22
+ "company_name",
23
+ "title",
24
+ "sent_datetime",
25
+ "issue_datetime",
26
+ "has_attachment",
27
+ "has_pdf",
28
+ "url",
29
+ "attachment_url",
30
+ "pdf_url",
31
+ "excel_url",
32
+ ],
33
+ }
34
+
35
+ _income_statements = {
36
+ "rep": [
37
+ "symbol",
38
+ "company_name",
39
+ "title",
40
+ "issue_datetime",
41
+ "period_end_to_date",
42
+ "revenue",
43
+ "cost_of_goods_sold",
44
+ "gross_profit",
45
+ "sales_general_and_administrative_expense",
46
+ "cost_of_decrease_in_receivables_value(exceptional_cost)",
47
+ "other_operating_revenue",
48
+ "other_operating_expenses",
49
+ "operating_income",
50
+ "finance_expense",
51
+ "net_miscellaneous_revenue",
52
+ "net_income_from_continuing_operations_before_tax",
53
+ "taxes",
54
+ "net_income_from_continuing_operation",
55
+ "discontinued_operations_profit",
56
+ "net_income",
57
+ "earning_per_share",
58
+ "listed_capital",
59
+ "url",
60
+ ]
61
+ }
62
+
63
+ _balance_sheet = {
64
+ "rep": [
65
+ "symbol",
66
+ "company_name",
67
+ "title",
68
+ "issue_datetime",
69
+ "period_end_to_date",
70
+ "tangible_fixed_assets",
71
+ "investment_property",
72
+ "intangible_assets",
73
+ "long_term_investments",
74
+ "long_term_receivables",
75
+ "other_assets",
76
+ "total_non_current_assets",
77
+ "prepayments",
78
+ "inventories",
79
+ "trade_and_other_receivables",
80
+ "short_term_investments",
81
+ "cash_and_equivalents",
82
+ "asset_for_sale",
83
+ "total_current_assets",
84
+ "total_assets",
85
+ "common_stock",
86
+ "received_for_capital_advance",
87
+ "capital_surplus",
88
+ "treasury_stock_surplus",
89
+ "legal_reserve",
90
+ "expansion_reserve",
91
+ "revaluation_surplus",
92
+ "exchange_differences_on_translation",
93
+ "retained_earnings",
94
+ "treasury_stock",
95
+ "total_shareholders_equity",
96
+ "long_term_liabilities",
97
+ "long_term_debt",
98
+ "allowance_for_post_retirement",
99
+ "total_non_current_liabilities",
100
+ "trade_and_other_liabilities",
101
+ "deferred_tax_liabilities",
102
+ "dividends_payable",
103
+ "loan_payable",
104
+ "provisions",
105
+ "deferred_revenue",
106
+ "liabilities_related_to_assets_for_sale",
107
+ "total_current_liabilities",
108
+ "total_liabilities",
109
+ "total_liabilities_and_shareholders_equities",
110
+ "url",
111
+ ]
112
+ }
113
+
114
+ letters = Property(
115
+ rename=_letters.get("rename"), drop=_letters.get("drop"), rep=_letters.get("rep")
116
+ )
117
+ income_statements = Property(
118
+ rename=_income_statements.get("rename"),
119
+ drop=_income_statements.get("drop"),
120
+ rep=_income_statements.get("rep"),
121
+ )
122
+ balance_sheet = Property(
123
+ rename=_balance_sheet.get("rename"),
124
+ drop=_balance_sheet.get("drop"),
125
+ rep=_balance_sheet.get("rep"),
126
+ )
127
+
128
+ cols = Cols(letters=letters, income_statements=income_statements, balance_sheet=balance_sheet)
@@ -0,0 +1,148 @@
1
+ from urllib.parse import urlencode
2
+
3
+
4
+ class QueryParameters:
5
+ def __init__(self, **kwargs):
6
+ super().__init__(**kwargs)
7
+ self._symbol = "فملی"
8
+ self._audited = "true"
9
+ self._category = 1
10
+ self._childes = "false"
11
+ self._length = -1
12
+ self._mains = "true"
13
+ self._page_number = 1
14
+
15
+ @property
16
+ def symbol(self):
17
+ return self._symbol
18
+
19
+ @symbol.setter
20
+ def symbol(self, symbol):
21
+ self._symbol = symbol
22
+
23
+ @property
24
+ def audited(self):
25
+ return self._audited
26
+
27
+ @audited.setter
28
+ def audited(self, audited: bool):
29
+ if audited:
30
+ self._audited = "true"
31
+ elif not audited:
32
+ self._audited = "false"
33
+
34
+ @property
35
+ def category(self):
36
+ return self._category
37
+
38
+ @category.setter
39
+ def category(self, category: int):
40
+ match category:
41
+ case 1:
42
+ self._category = category
43
+ case 2:
44
+ self._category = category
45
+ case 3:
46
+ self._category = category
47
+ case _:
48
+ self._category = -1
49
+
50
+ @property
51
+ def childes(self):
52
+ return self._childes
53
+
54
+ @childes.setter
55
+ def childes(self, childes: bool):
56
+ if childes:
57
+ self._childes = "true"
58
+ elif not childes:
59
+ self._childes = "false"
60
+
61
+ @property
62
+ def length(self):
63
+ return self._length
64
+
65
+ @length.setter
66
+ def length(self, length: int):
67
+ if self._category == 1:
68
+ match length:
69
+ case 3:
70
+ self._length = length
71
+ case 6:
72
+ self._length = length
73
+ case 12:
74
+ self._length = length
75
+ case _:
76
+ self._length = -1
77
+ elif length in range(1, 13):
78
+ self._length = length
79
+ else:
80
+ self._length = -1
81
+
82
+ @property
83
+ def mains(self):
84
+ return self._mains
85
+
86
+ @mains.setter
87
+ def mains(self, mains: bool):
88
+ if mains:
89
+ self._mains = "true"
90
+ elif not mains:
91
+ self._mains = "false"
92
+
93
+ @property
94
+ def page_number(self):
95
+ return self._page_number
96
+
97
+ @page_number.setter
98
+ def page_number(self, page_number):
99
+ self._page_number = page_number
100
+
101
+ @property
102
+ def parameters(self):
103
+ return {
104
+ "Audited": self._audited, # حسابرسی شده
105
+ "AuditorRef": -1, #
106
+ "Category": self._category, #
107
+ "Childs": self._childes, # زیرمجموعه
108
+ "CompanyState": 0, #
109
+ "CompanyType": 1, #
110
+ "Consolidatable": "true", # تلفیقی
111
+ "FromDate": "1395/01/01",
112
+ "IsNotAudited": "false", # حسابرسی نشده
113
+ "Isic": 271018, #
114
+ "Length": self._length, # طولِ دوره
115
+ "LetterType": 6, # نوعِ اطلاعیه
116
+ "Mains": self._mains, # اصلی
117
+ "NotAudited": "false", #
118
+ "NotConsolidatable": "true", #
119
+ "PageNumber": self._page_number, #
120
+ "Publisher": "false", #
121
+ "Symbol": self._symbol, # نماد
122
+ # "ToDate": "1402/05/03",
123
+ "TracingNo": -1, #
124
+ "search": "true",
125
+ }
126
+
127
+ @property
128
+ def query_parameters(self):
129
+ return urlencode(self.parameters)
130
+
131
+
132
+ class URL(QueryParameters):
133
+ def __init__(
134
+ self,
135
+ base_url="https://codal.ir",
136
+ api="https://search.codal.ir/api/search/v2/q?",
137
+ **kwargs,
138
+ ):
139
+ super().__init__(**kwargs)
140
+ self.base_url = base_url
141
+ self.api = api
142
+
143
+ @property
144
+ def search_url(self):
145
+ return self.api + self.query_parameters
146
+
147
+ def financial_statements(self, letter_url, sheet_id):
148
+ return self.base_url + f"{letter_url}&sheetId={sheet_id}"