financegy 0.1.0__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.
- financegy-0.1.0/LICENSE +21 -0
- financegy-0.1.0/PKG-INFO +121 -0
- financegy-0.1.0/README.md +107 -0
- financegy-0.1.0/financegy/__init__.py +27 -0
- financegy-0.1.0/financegy/config.py +7 -0
- financegy-0.1.0/financegy/core/parser.py +278 -0
- financegy-0.1.0/financegy/core/request_handler.py +8 -0
- financegy-0.1.0/financegy/modules/securities.py +94 -0
- financegy-0.1.0/financegy.egg-info/PKG-INFO +121 -0
- financegy-0.1.0/financegy.egg-info/SOURCES.txt +14 -0
- financegy-0.1.0/financegy.egg-info/dependency_links.txt +1 -0
- financegy-0.1.0/financegy.egg-info/requires.txt +2 -0
- financegy-0.1.0/financegy.egg-info/top_level.txt +1 -0
- financegy-0.1.0/pyproject.toml +16 -0
- financegy-0.1.0/setup.cfg +4 -0
- financegy-0.1.0/tests/test_securities.py +37 -0
financegy-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Ezra Minty
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
financegy-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: financegy
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Unofficial Python library for accessing GSE (Guyana Stock Exchange) financial data
|
|
5
|
+
Author-email: Ezra Minty <ezranminty@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/xbze3/financegy
|
|
8
|
+
Project-URL: Issues, https://github.com/xbze3/financegy/issues
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: requests
|
|
12
|
+
Requires-Dist: beautifulsoup4
|
|
13
|
+
Dynamic: license-file
|
|
14
|
+
|
|
15
|
+
# 🏦 FinanceGY
|
|
16
|
+
|
|
17
|
+
**FinanceGY** is an unofficial Python library for accessing financial data from the **Guyana Stock Exchange (GSE)**. It provides a simple and consistent interface for retrieving information on traded securities, recent trade data, and session details, all programmatically.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install financegy
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
import financegy
|
|
33
|
+
|
|
34
|
+
# Get a list of all traded securities
|
|
35
|
+
securities = financegy.get_securities()
|
|
36
|
+
|
|
37
|
+
# Get the name of a security by its ticker symbol
|
|
38
|
+
security_name = financegy.get_security_by_symbol("DDL")
|
|
39
|
+
|
|
40
|
+
# Get the most recent trade data for a security
|
|
41
|
+
recent_trade = financegy.get_recent_trade("DDL")
|
|
42
|
+
|
|
43
|
+
# Get all trade data for the most recent year
|
|
44
|
+
recent_year = financegy.get_security_recent_year("DDL")
|
|
45
|
+
|
|
46
|
+
# Get trade data for a specific trading session
|
|
47
|
+
session_trades = financegy.get_session_trades("1136")
|
|
48
|
+
|
|
49
|
+
# Get session trade data for a specific security
|
|
50
|
+
security_session_trade = financegy.get_security_session_trade("DDL", "1136")
|
|
51
|
+
|
|
52
|
+
# Search for securities by name or symbol
|
|
53
|
+
search_results = financegy.search_securities("DDL")
|
|
54
|
+
|
|
55
|
+
# Get all trades for a given year
|
|
56
|
+
year_trades = financegy.get_trades_for_year("DDL", "2019")
|
|
57
|
+
|
|
58
|
+
# Get historical trades within a date range (dd/mm/yyyy)
|
|
59
|
+
historical_trades = financegy.get_historical_trades(
|
|
60
|
+
symbol="DDL",
|
|
61
|
+
start_date="01/06/2020",
|
|
62
|
+
end_date="01/01/2022"
|
|
63
|
+
)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Function Overview
|
|
69
|
+
|
|
70
|
+
#### `get_securities()`
|
|
71
|
+
|
|
72
|
+
Returns a list of all currently traded securities on the Guyana Stock Exchange.
|
|
73
|
+
|
|
74
|
+
#### `get_security_by_symbol(symbol: str)`
|
|
75
|
+
|
|
76
|
+
Retrieves the full name of a security using its ticker symbol (e.g., `"DDL"` → `"Demerara Distillers Limited"`).
|
|
77
|
+
|
|
78
|
+
#### `get_recent_trade(symbol: str)`
|
|
79
|
+
|
|
80
|
+
Returns the most recent trade information for the given security.
|
|
81
|
+
|
|
82
|
+
#### `get_security_recent_year(symbol: str)`
|
|
83
|
+
|
|
84
|
+
Fetches all trade data for the most recent year of the selected security.
|
|
85
|
+
|
|
86
|
+
#### `get_session_trades(session: str)`
|
|
87
|
+
|
|
88
|
+
Retrieves trade data for _all_ securities during a specific trading session.
|
|
89
|
+
|
|
90
|
+
#### `get_security_session_trade(symbol: str, session: str)`
|
|
91
|
+
|
|
92
|
+
Retrieves trade data for a specific security in a given trading session.
|
|
93
|
+
|
|
94
|
+
#### `search_securities(query: str)`
|
|
95
|
+
|
|
96
|
+
Searches for securities whose names or ticker symbols match the given query.
|
|
97
|
+
|
|
98
|
+
#### `get_trades_for_year(symbol: str, year: str)`
|
|
99
|
+
|
|
100
|
+
Returns all trade records for a specific security during a given year.
|
|
101
|
+
|
|
102
|
+
#### `get_historical_trades(symbol: str, start_date: str, end_date: str)`
|
|
103
|
+
|
|
104
|
+
Fetches historical trade data for a security within the specified date range (`dd/mm/yyyy` format).
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
This project is licensed under the **MIT License**
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Example Use Case
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
import financegy
|
|
118
|
+
|
|
119
|
+
ddl_recent = financegy.get_security_recent("DDL")
|
|
120
|
+
print(ddl_recent)
|
|
121
|
+
```
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# 🏦 FinanceGY
|
|
2
|
+
|
|
3
|
+
**FinanceGY** is an unofficial Python library for accessing financial data from the **Guyana Stock Exchange (GSE)**. It provides a simple and consistent interface for retrieving information on traded securities, recent trade data, and session details, all programmatically.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install financegy
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
import financegy
|
|
19
|
+
|
|
20
|
+
# Get a list of all traded securities
|
|
21
|
+
securities = financegy.get_securities()
|
|
22
|
+
|
|
23
|
+
# Get the name of a security by its ticker symbol
|
|
24
|
+
security_name = financegy.get_security_by_symbol("DDL")
|
|
25
|
+
|
|
26
|
+
# Get the most recent trade data for a security
|
|
27
|
+
recent_trade = financegy.get_recent_trade("DDL")
|
|
28
|
+
|
|
29
|
+
# Get all trade data for the most recent year
|
|
30
|
+
recent_year = financegy.get_security_recent_year("DDL")
|
|
31
|
+
|
|
32
|
+
# Get trade data for a specific trading session
|
|
33
|
+
session_trades = financegy.get_session_trades("1136")
|
|
34
|
+
|
|
35
|
+
# Get session trade data for a specific security
|
|
36
|
+
security_session_trade = financegy.get_security_session_trade("DDL", "1136")
|
|
37
|
+
|
|
38
|
+
# Search for securities by name or symbol
|
|
39
|
+
search_results = financegy.search_securities("DDL")
|
|
40
|
+
|
|
41
|
+
# Get all trades for a given year
|
|
42
|
+
year_trades = financegy.get_trades_for_year("DDL", "2019")
|
|
43
|
+
|
|
44
|
+
# Get historical trades within a date range (dd/mm/yyyy)
|
|
45
|
+
historical_trades = financegy.get_historical_trades(
|
|
46
|
+
symbol="DDL",
|
|
47
|
+
start_date="01/06/2020",
|
|
48
|
+
end_date="01/01/2022"
|
|
49
|
+
)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Function Overview
|
|
55
|
+
|
|
56
|
+
#### `get_securities()`
|
|
57
|
+
|
|
58
|
+
Returns a list of all currently traded securities on the Guyana Stock Exchange.
|
|
59
|
+
|
|
60
|
+
#### `get_security_by_symbol(symbol: str)`
|
|
61
|
+
|
|
62
|
+
Retrieves the full name of a security using its ticker symbol (e.g., `"DDL"` → `"Demerara Distillers Limited"`).
|
|
63
|
+
|
|
64
|
+
#### `get_recent_trade(symbol: str)`
|
|
65
|
+
|
|
66
|
+
Returns the most recent trade information for the given security.
|
|
67
|
+
|
|
68
|
+
#### `get_security_recent_year(symbol: str)`
|
|
69
|
+
|
|
70
|
+
Fetches all trade data for the most recent year of the selected security.
|
|
71
|
+
|
|
72
|
+
#### `get_session_trades(session: str)`
|
|
73
|
+
|
|
74
|
+
Retrieves trade data for _all_ securities during a specific trading session.
|
|
75
|
+
|
|
76
|
+
#### `get_security_session_trade(symbol: str, session: str)`
|
|
77
|
+
|
|
78
|
+
Retrieves trade data for a specific security in a given trading session.
|
|
79
|
+
|
|
80
|
+
#### `search_securities(query: str)`
|
|
81
|
+
|
|
82
|
+
Searches for securities whose names or ticker symbols match the given query.
|
|
83
|
+
|
|
84
|
+
#### `get_trades_for_year(symbol: str, year: str)`
|
|
85
|
+
|
|
86
|
+
Returns all trade records for a specific security during a given year.
|
|
87
|
+
|
|
88
|
+
#### `get_historical_trades(symbol: str, start_date: str, end_date: str)`
|
|
89
|
+
|
|
90
|
+
Fetches historical trade data for a security within the specified date range (`dd/mm/yyyy` format).
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## License
|
|
95
|
+
|
|
96
|
+
This project is licensed under the **MIT License**
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Example Use Case
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
import financegy
|
|
104
|
+
|
|
105
|
+
ddl_recent = financegy.get_security_recent("DDL")
|
|
106
|
+
print(ddl_recent)
|
|
107
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""FinanceGY - a Python library for accessing data from the Guyana Stock Exchange."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
4
|
+
|
|
5
|
+
from financegy.modules.securities import(
|
|
6
|
+
get_securities,
|
|
7
|
+
get_security_by_symbol,
|
|
8
|
+
get_recent_trade,
|
|
9
|
+
get_security_recent_year,
|
|
10
|
+
get_session_trades,
|
|
11
|
+
get_security_session_trade,
|
|
12
|
+
search_securities,
|
|
13
|
+
get_trades_for_year,
|
|
14
|
+
get_historical_trades
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"get_securities",
|
|
19
|
+
"get_security_by_symbol",
|
|
20
|
+
"get_recent_trade",
|
|
21
|
+
"get_security_recent_year",
|
|
22
|
+
"get_session_trades",
|
|
23
|
+
"get_security_session_trade",
|
|
24
|
+
"search_securities",
|
|
25
|
+
"get_trades_for_year",
|
|
26
|
+
"get_historical_trades"
|
|
27
|
+
]
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
from bs4 import BeautifulSoup
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
|
|
4
|
+
def parse_get_securities(html: str):
|
|
5
|
+
"""Extract security info"""
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
soup = BeautifulSoup(html, "html.parser")
|
|
9
|
+
security_info_html = soup.find("div", class_="securities")
|
|
10
|
+
|
|
11
|
+
if not security_info_html:
|
|
12
|
+
return []
|
|
13
|
+
|
|
14
|
+
security_info = []
|
|
15
|
+
securities = security_info_html.find_all("div", class_="security group")
|
|
16
|
+
|
|
17
|
+
for security in securities:
|
|
18
|
+
symbol = security.find_all("div", class_="acronym inline")[0].get_text(strip=True)
|
|
19
|
+
name = security.find_all("div", class_="name inline")[0].get_text(strip=True)
|
|
20
|
+
|
|
21
|
+
security_info.append({
|
|
22
|
+
"symbol": symbol,
|
|
23
|
+
"name": name
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
return security_info
|
|
28
|
+
|
|
29
|
+
except Exception as e:
|
|
30
|
+
print(f"[parse_get_securities] Error parsing securities: {e}")
|
|
31
|
+
|
|
32
|
+
def parse_get_security_recent_year(html: str):
|
|
33
|
+
"""Extract selected security's trade info from current year"""
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
soup = BeautifulSoup(html, "html.parser")
|
|
37
|
+
|
|
38
|
+
security_info_html = soup.find("div", class_="year slide")
|
|
39
|
+
if not security_info_html:
|
|
40
|
+
raise ValueError("Could not find 'div.year.slide' section in HTML.")
|
|
41
|
+
|
|
42
|
+
trade_data = []
|
|
43
|
+
|
|
44
|
+
trades = security_info_html.find_all("tr", class_="trade")
|
|
45
|
+
if not trades:
|
|
46
|
+
raise ValueError("No trade rows found for this security.")
|
|
47
|
+
|
|
48
|
+
def safe_text(parent, class_name):
|
|
49
|
+
cell = parent.find("td", class_=class_name)
|
|
50
|
+
return cell.get_text(strip=True) if cell else None
|
|
51
|
+
|
|
52
|
+
for trade in trades:
|
|
53
|
+
trade_data.append({
|
|
54
|
+
"session": safe_text(trade, "session"),
|
|
55
|
+
"date": safe_text(trade, "date"),
|
|
56
|
+
"ltp": safe_text(trade, "name"),
|
|
57
|
+
"best_bid": safe_text(trade, "best bid"),
|
|
58
|
+
"vol_bid": safe_text(trade, "vol bid"),
|
|
59
|
+
"best_offer": safe_text(trade, "best offer"),
|
|
60
|
+
"vol_offer": safe_text(trade, "vol offer"),
|
|
61
|
+
"opening_price": safe_text(trade, "opening price"),
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
return trade_data
|
|
65
|
+
|
|
66
|
+
except Exception as e:
|
|
67
|
+
print(f"[parse_get_security_recent_year] Error parsing HTML: {e}")
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
def parse_get_recent_trade(html: str):
|
|
71
|
+
"""Extract selected security's most recent trade info"""
|
|
72
|
+
try:
|
|
73
|
+
soup = BeautifulSoup(html, "html.parser")
|
|
74
|
+
|
|
75
|
+
security_info_html = soup.find("div", class_="year slide")
|
|
76
|
+
if not security_info_html:
|
|
77
|
+
raise ValueError("Could not find 'div.year.slide' section in HTML.")
|
|
78
|
+
|
|
79
|
+
trades = security_info_html.find_all("tr", class_="trade")
|
|
80
|
+
if not trades:
|
|
81
|
+
raise ValueError("No trade rows found for this security.")
|
|
82
|
+
|
|
83
|
+
recent = trades[-1]
|
|
84
|
+
|
|
85
|
+
def safe_text(parent, class_name):
|
|
86
|
+
cell = parent.find("td", class_=class_name)
|
|
87
|
+
return cell.get_text(strip=True) if cell else None
|
|
88
|
+
|
|
89
|
+
recent_info = {
|
|
90
|
+
"session": safe_text(recent, "session"),
|
|
91
|
+
"date": safe_text(recent, "date"),
|
|
92
|
+
"ltp": safe_text(recent, "name"),
|
|
93
|
+
"best_bid": safe_text(recent, "best bid"),
|
|
94
|
+
"vol_bid": safe_text(recent, "vol bid"),
|
|
95
|
+
"best_offer": safe_text(recent, "best offer"),
|
|
96
|
+
"vol_offer": safe_text(recent, "vol offer"),
|
|
97
|
+
"opening_price": safe_text(recent, "opening price"),
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return recent_info
|
|
101
|
+
|
|
102
|
+
except Exception as e:
|
|
103
|
+
print(f"[parse_get_security_recent] Error parsing HTML: {e}")
|
|
104
|
+
return None
|
|
105
|
+
|
|
106
|
+
def parse_get_session_trades(html: str):
|
|
107
|
+
"""Extract session data for all securities"""
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
soup = BeautifulSoup(html, "html.parser")
|
|
111
|
+
|
|
112
|
+
sessions_info_html = soup.find("div", class_="session")
|
|
113
|
+
if not sessions_info_html:
|
|
114
|
+
raise ValueError("Could not find 'div.session' section in HTML.")
|
|
115
|
+
|
|
116
|
+
sessions = sessions_info_html.find_all("tr", class_="trade")
|
|
117
|
+
if not sessions:
|
|
118
|
+
raise ValueError("No session data found.")
|
|
119
|
+
|
|
120
|
+
def safe_text(parent, class_name):
|
|
121
|
+
cell = parent.find("td", class_=class_name)
|
|
122
|
+
return cell.get_text(strip=True) if cell else None
|
|
123
|
+
|
|
124
|
+
session_data = []
|
|
125
|
+
|
|
126
|
+
for session in sessions:
|
|
127
|
+
session_data.append({
|
|
128
|
+
"symbol": safe_text(session, "mnemonic"),
|
|
129
|
+
"ltp": safe_text(session, "name"),
|
|
130
|
+
"best_bid": safe_text(session, "best bid"),
|
|
131
|
+
"vol_bid": safe_text(session, "vol bid"),
|
|
132
|
+
"best_offer": safe_text(session, "best offer"),
|
|
133
|
+
"vol_offer": safe_text(session, "vol offer"),
|
|
134
|
+
"opening_price": safe_text(session, "opening price"),
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
return session_data
|
|
138
|
+
|
|
139
|
+
except Exception as e:
|
|
140
|
+
print(f"[parse_get_securities_session] Error parsing HTML: {e}")
|
|
141
|
+
return None
|
|
142
|
+
|
|
143
|
+
def parse_get_security_session_trade(symbol: str, html: str):
|
|
144
|
+
"""Extract session data for given security"""
|
|
145
|
+
|
|
146
|
+
try:
|
|
147
|
+
soup = BeautifulSoup(html, "html.parser")
|
|
148
|
+
|
|
149
|
+
sessions_info_html = soup.find("div", class_="session")
|
|
150
|
+
if not sessions_info_html:
|
|
151
|
+
raise ValueError("Could not find 'div.session' section in HTML.")
|
|
152
|
+
|
|
153
|
+
sessions = sessions_info_html.find_all("tr", class_="trade")
|
|
154
|
+
if not sessions:
|
|
155
|
+
raise ValueError("No session data found.")
|
|
156
|
+
|
|
157
|
+
def safe_text(parent, class_name):
|
|
158
|
+
cell = parent.find("td", class_=class_name)
|
|
159
|
+
return cell.get_text(strip=True) if cell else None
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
for session in sessions:
|
|
163
|
+
session_symbol = safe_text(session, "mnemonic")
|
|
164
|
+
|
|
165
|
+
if (session_symbol == symbol):
|
|
166
|
+
session_data = {
|
|
167
|
+
"symbol": safe_text(session, "mnemonic"),
|
|
168
|
+
"ltp": safe_text(session, "name"),
|
|
169
|
+
"best_bid": safe_text(session, "best bid"),
|
|
170
|
+
"vol_bid": safe_text(session, "vol bid"),
|
|
171
|
+
"best_offer": safe_text(session, "best offer"),
|
|
172
|
+
"vol_offer": safe_text(session, "vol offer"),
|
|
173
|
+
"opening_price": safe_text(session, "opening price"),
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return session_data
|
|
177
|
+
|
|
178
|
+
except Exception as e:
|
|
179
|
+
print(f"[parse_get_security_session] Error parsing HTML: {e}")
|
|
180
|
+
return None
|
|
181
|
+
|
|
182
|
+
def parse_get_trades_for_year(year: str, html: str):
|
|
183
|
+
"""Get security trade information from a specific year"""
|
|
184
|
+
|
|
185
|
+
try:
|
|
186
|
+
soup = BeautifulSoup(html, "html.parser")
|
|
187
|
+
|
|
188
|
+
security_info_html = soup.find("div", class_="year slide", id=year)
|
|
189
|
+
if not security_info_html:
|
|
190
|
+
raise ValueError("Could not find 'div.year.slide' section in HTML.")
|
|
191
|
+
|
|
192
|
+
trade_data = []
|
|
193
|
+
|
|
194
|
+
trades = security_info_html.find_all("tr", class_="trade")
|
|
195
|
+
if not trades:
|
|
196
|
+
raise ValueError("No trade rows found for this security.")
|
|
197
|
+
|
|
198
|
+
def safe_text(parent, class_name):
|
|
199
|
+
cell = parent.find("td", class_=class_name)
|
|
200
|
+
return cell.get_text(strip=True) if cell else None
|
|
201
|
+
|
|
202
|
+
for trade in trades:
|
|
203
|
+
trade_data.append({
|
|
204
|
+
"session": safe_text(trade, "session"),
|
|
205
|
+
"date": safe_text(trade, "date"),
|
|
206
|
+
"ltp": safe_text(trade, "name"),
|
|
207
|
+
"best_bid": safe_text(trade, "best bid"),
|
|
208
|
+
"vol_bid": safe_text(trade, "vol bid"),
|
|
209
|
+
"best_offer": safe_text(trade, "best offer"),
|
|
210
|
+
"vol_offer": safe_text(trade, "vol offer"),
|
|
211
|
+
"opening_price": safe_text(trade, "opening price"),
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
return trade_data
|
|
215
|
+
|
|
216
|
+
except Exception as e:
|
|
217
|
+
print(f"[parse_get_security_recent_year] Error parsing HTML: {e}")
|
|
218
|
+
return None
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def parse_get_historical_trades(start_date: str, end_date: str, html: str):
|
|
222
|
+
"""Parse historical trade data from HTML between given dates (DD/MM/YYYY)"""
|
|
223
|
+
|
|
224
|
+
try:
|
|
225
|
+
start = datetime.strptime(start_date, "%d/%m/%Y")
|
|
226
|
+
end = datetime.strptime(end_date, "%d/%m/%Y")
|
|
227
|
+
|
|
228
|
+
soup = BeautifulSoup(html, "html.parser")
|
|
229
|
+
|
|
230
|
+
year_sections = soup.find_all("div", class_="year slide")
|
|
231
|
+
if not year_sections:
|
|
232
|
+
raise ValueError("No 'div.year.slide' sections found in HTML.")
|
|
233
|
+
|
|
234
|
+
trade_data = []
|
|
235
|
+
|
|
236
|
+
def safe_text(parent, class_name):
|
|
237
|
+
cell = parent.find("td", class_=class_name)
|
|
238
|
+
return cell.get_text(strip=True) if cell else None
|
|
239
|
+
|
|
240
|
+
for section in year_sections:
|
|
241
|
+
year_id = section.get("id")
|
|
242
|
+
if not year_id or not year_id.isdigit():
|
|
243
|
+
continue
|
|
244
|
+
|
|
245
|
+
year = int(year_id)
|
|
246
|
+
if year < start.year or year > end.year:
|
|
247
|
+
continue
|
|
248
|
+
|
|
249
|
+
trades = section.find_all("tr", class_="trade")
|
|
250
|
+
for trade in trades:
|
|
251
|
+
date_text = safe_text(trade, "date")
|
|
252
|
+
if not date_text:
|
|
253
|
+
continue
|
|
254
|
+
|
|
255
|
+
try:
|
|
256
|
+
trade_date = datetime.strptime(date_text, "%d/%m/%Y")
|
|
257
|
+
except ValueError:
|
|
258
|
+
continue
|
|
259
|
+
|
|
260
|
+
if start <= trade_date <= end:
|
|
261
|
+
trade_data.append({
|
|
262
|
+
"session": safe_text(trade, "session"),
|
|
263
|
+
"date": date_text,
|
|
264
|
+
"ltp": safe_text(trade, "name"),
|
|
265
|
+
"best_bid": safe_text(trade, "best bid"),
|
|
266
|
+
"vol_bid": safe_text(trade, "vol bid"),
|
|
267
|
+
"best_offer": safe_text(trade, "best offer"),
|
|
268
|
+
"vol_offer": safe_text(trade, "vol offer"),
|
|
269
|
+
"opening_price": safe_text(trade, "opening price"),
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
trade_data.sort(key=lambda x: datetime.strptime(x["date"], "%d/%m/%Y"))
|
|
273
|
+
|
|
274
|
+
return trade_data
|
|
275
|
+
|
|
276
|
+
except Exception as e:
|
|
277
|
+
print(f"[parse_get_historical_trades] Error parsing HTML: {e}")
|
|
278
|
+
return None
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from ..config import BASE_URL, HEADERS, REQUEST_TIMEOUT
|
|
3
|
+
|
|
4
|
+
def fetch_page(endpoint: str):
|
|
5
|
+
url = f"{BASE_URL}{endpoint}"
|
|
6
|
+
response = requests.get(url, headers=HEADERS, timeout=REQUEST_TIMEOUT)
|
|
7
|
+
response.raise_for_status()
|
|
8
|
+
return response.text
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
from financegy.core import request_handler, parser
|
|
2
|
+
|
|
3
|
+
def get_securities():
|
|
4
|
+
"""Get names of all currently traded securities"""
|
|
5
|
+
path = "/securities/"
|
|
6
|
+
html = request_handler.fetch_page(path)
|
|
7
|
+
return parser.parse_get_securities(html);
|
|
8
|
+
|
|
9
|
+
def get_security_by_symbol(symbol: str):
|
|
10
|
+
"""Get the security details by its ticker symbol"""
|
|
11
|
+
securities = get_securities()
|
|
12
|
+
|
|
13
|
+
symbol = symbol.strip().upper()
|
|
14
|
+
|
|
15
|
+
return next(
|
|
16
|
+
(security['name'] for security in securities if security["symbol"].upper() == symbol),
|
|
17
|
+
None,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
def get_security_recent_year(symbol:str):
|
|
21
|
+
"""Get the most recent year's trade data for any of the traded securities"""
|
|
22
|
+
|
|
23
|
+
security_name = get_security_by_symbol(symbol)
|
|
24
|
+
security_name = security_name.lower().replace(" ", "-")
|
|
25
|
+
|
|
26
|
+
path = "/security/" + security_name
|
|
27
|
+
html = request_handler.fetch_page(path)
|
|
28
|
+
return parser.parse_get_security_recent_year(html)
|
|
29
|
+
|
|
30
|
+
def get_recent_trade(symbol: str):
|
|
31
|
+
"""Get the most recent trade data for any of the traded securities"""
|
|
32
|
+
|
|
33
|
+
security_name = get_security_by_symbol(symbol)
|
|
34
|
+
security_name = security_name.lower().replace(" ", "-")
|
|
35
|
+
|
|
36
|
+
path = "/security/" + security_name
|
|
37
|
+
html = request_handler.fetch_page(path)
|
|
38
|
+
return parser.parse_get_recent_trade(html)
|
|
39
|
+
|
|
40
|
+
def get_session_trades(session: str):
|
|
41
|
+
"""Get the session trade data for all the available securities"""
|
|
42
|
+
|
|
43
|
+
path = f"/financial_session/{session}/"
|
|
44
|
+
html = request_handler.fetch_page(path)
|
|
45
|
+
return parser.parse_get_session_trades(html)
|
|
46
|
+
|
|
47
|
+
def get_security_session_trade(symbol: str, session: str):
|
|
48
|
+
"""Get the session trade data for a given security"""
|
|
49
|
+
|
|
50
|
+
symbol = symbol.strip().upper()
|
|
51
|
+
|
|
52
|
+
path = f"/financial_session/{session}/"
|
|
53
|
+
html = request_handler.fetch_page(path)
|
|
54
|
+
return parser.parse_get_security_session_trade(symbol, html)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def get_trades_for_year(symbol: str, year: str):
|
|
58
|
+
"""Get security trade information from a specific year"""
|
|
59
|
+
|
|
60
|
+
symbol = symbol.strip().upper()
|
|
61
|
+
|
|
62
|
+
security_name = get_security_by_symbol(symbol)
|
|
63
|
+
security_name = security_name.lower().replace(" ", "-")
|
|
64
|
+
|
|
65
|
+
path = f"/security/{security_name}/"
|
|
66
|
+
html = request_handler.fetch_page(path)
|
|
67
|
+
|
|
68
|
+
return parser.parse_get_trades_for_year(year, html)
|
|
69
|
+
|
|
70
|
+
def get_historical_trades(symbol: str, start_date: str, end_date: str):
|
|
71
|
+
"""Get historical trade data for a date range"""
|
|
72
|
+
|
|
73
|
+
symbol = symbol.strip().upper()
|
|
74
|
+
|
|
75
|
+
security_name = get_security_by_symbol(symbol)
|
|
76
|
+
security_name = security_name.lower().replace(" ", "-")
|
|
77
|
+
|
|
78
|
+
path = f"/security/{security_name}/"
|
|
79
|
+
html = request_handler.fetch_page(path)
|
|
80
|
+
|
|
81
|
+
return parser.parse_get_historical_trades(start_date, end_date, html)
|
|
82
|
+
|
|
83
|
+
def search_securities(query: str):
|
|
84
|
+
"""Search securities by symbol or name (partial match)"""
|
|
85
|
+
|
|
86
|
+
query = query.lower().strip()
|
|
87
|
+
all_securities = get_securities()
|
|
88
|
+
|
|
89
|
+
matches = [
|
|
90
|
+
sec for sec in all_securities
|
|
91
|
+
if query in sec["symbol"].lower() or query in sec["name"].lower()
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
return matches
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: financegy
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Unofficial Python library for accessing GSE (Guyana Stock Exchange) financial data
|
|
5
|
+
Author-email: Ezra Minty <ezranminty@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/xbze3/financegy
|
|
8
|
+
Project-URL: Issues, https://github.com/xbze3/financegy/issues
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: requests
|
|
12
|
+
Requires-Dist: beautifulsoup4
|
|
13
|
+
Dynamic: license-file
|
|
14
|
+
|
|
15
|
+
# 🏦 FinanceGY
|
|
16
|
+
|
|
17
|
+
**FinanceGY** is an unofficial Python library for accessing financial data from the **Guyana Stock Exchange (GSE)**. It provides a simple and consistent interface for retrieving information on traded securities, recent trade data, and session details, all programmatically.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install financegy
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
import financegy
|
|
33
|
+
|
|
34
|
+
# Get a list of all traded securities
|
|
35
|
+
securities = financegy.get_securities()
|
|
36
|
+
|
|
37
|
+
# Get the name of a security by its ticker symbol
|
|
38
|
+
security_name = financegy.get_security_by_symbol("DDL")
|
|
39
|
+
|
|
40
|
+
# Get the most recent trade data for a security
|
|
41
|
+
recent_trade = financegy.get_recent_trade("DDL")
|
|
42
|
+
|
|
43
|
+
# Get all trade data for the most recent year
|
|
44
|
+
recent_year = financegy.get_security_recent_year("DDL")
|
|
45
|
+
|
|
46
|
+
# Get trade data for a specific trading session
|
|
47
|
+
session_trades = financegy.get_session_trades("1136")
|
|
48
|
+
|
|
49
|
+
# Get session trade data for a specific security
|
|
50
|
+
security_session_trade = financegy.get_security_session_trade("DDL", "1136")
|
|
51
|
+
|
|
52
|
+
# Search for securities by name or symbol
|
|
53
|
+
search_results = financegy.search_securities("DDL")
|
|
54
|
+
|
|
55
|
+
# Get all trades for a given year
|
|
56
|
+
year_trades = financegy.get_trades_for_year("DDL", "2019")
|
|
57
|
+
|
|
58
|
+
# Get historical trades within a date range (dd/mm/yyyy)
|
|
59
|
+
historical_trades = financegy.get_historical_trades(
|
|
60
|
+
symbol="DDL",
|
|
61
|
+
start_date="01/06/2020",
|
|
62
|
+
end_date="01/01/2022"
|
|
63
|
+
)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Function Overview
|
|
69
|
+
|
|
70
|
+
#### `get_securities()`
|
|
71
|
+
|
|
72
|
+
Returns a list of all currently traded securities on the Guyana Stock Exchange.
|
|
73
|
+
|
|
74
|
+
#### `get_security_by_symbol(symbol: str)`
|
|
75
|
+
|
|
76
|
+
Retrieves the full name of a security using its ticker symbol (e.g., `"DDL"` → `"Demerara Distillers Limited"`).
|
|
77
|
+
|
|
78
|
+
#### `get_recent_trade(symbol: str)`
|
|
79
|
+
|
|
80
|
+
Returns the most recent trade information for the given security.
|
|
81
|
+
|
|
82
|
+
#### `get_security_recent_year(symbol: str)`
|
|
83
|
+
|
|
84
|
+
Fetches all trade data for the most recent year of the selected security.
|
|
85
|
+
|
|
86
|
+
#### `get_session_trades(session: str)`
|
|
87
|
+
|
|
88
|
+
Retrieves trade data for _all_ securities during a specific trading session.
|
|
89
|
+
|
|
90
|
+
#### `get_security_session_trade(symbol: str, session: str)`
|
|
91
|
+
|
|
92
|
+
Retrieves trade data for a specific security in a given trading session.
|
|
93
|
+
|
|
94
|
+
#### `search_securities(query: str)`
|
|
95
|
+
|
|
96
|
+
Searches for securities whose names or ticker symbols match the given query.
|
|
97
|
+
|
|
98
|
+
#### `get_trades_for_year(symbol: str, year: str)`
|
|
99
|
+
|
|
100
|
+
Returns all trade records for a specific security during a given year.
|
|
101
|
+
|
|
102
|
+
#### `get_historical_trades(symbol: str, start_date: str, end_date: str)`
|
|
103
|
+
|
|
104
|
+
Fetches historical trade data for a security within the specified date range (`dd/mm/yyyy` format).
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
This project is licensed under the **MIT License**
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Example Use Case
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
import financegy
|
|
118
|
+
|
|
119
|
+
ddl_recent = financegy.get_security_recent("DDL")
|
|
120
|
+
print(ddl_recent)
|
|
121
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
financegy/__init__.py
|
|
5
|
+
financegy/config.py
|
|
6
|
+
financegy.egg-info/PKG-INFO
|
|
7
|
+
financegy.egg-info/SOURCES.txt
|
|
8
|
+
financegy.egg-info/dependency_links.txt
|
|
9
|
+
financegy.egg-info/requires.txt
|
|
10
|
+
financegy.egg-info/top_level.txt
|
|
11
|
+
financegy/core/parser.py
|
|
12
|
+
financegy/core/request_handler.py
|
|
13
|
+
financegy/modules/securities.py
|
|
14
|
+
tests/test_securities.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
financegy
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "financegy"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Unofficial Python library for accessing GSE (Guyana Stock Exchange) financial data"
|
|
9
|
+
authors = [{ name = "Ezra Minty", email = "ezranminty@gmail.com" }]
|
|
10
|
+
dependencies = ["requests", "beautifulsoup4"]
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
license = { text = "MIT" }
|
|
13
|
+
|
|
14
|
+
[project.urls]
|
|
15
|
+
Homepage = "https://github.com/xbze3/financegy"
|
|
16
|
+
Issues = "https://github.com/xbze3/financegy/issues"
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from financegy import *
|
|
2
|
+
|
|
3
|
+
def test_get_securities():
|
|
4
|
+
result = get_securities()
|
|
5
|
+
assert isinstance(result, list)
|
|
6
|
+
|
|
7
|
+
def test_get_security_by_symbol():
|
|
8
|
+
result = get_security_by_symbol(symbol="ddl")
|
|
9
|
+
assert isinstance(result, (str, type(None)))
|
|
10
|
+
|
|
11
|
+
def test_get_recent_trade():
|
|
12
|
+
result = get_recent_trade(symbol="ddl")
|
|
13
|
+
assert isinstance(result, (dict, type(None)))
|
|
14
|
+
|
|
15
|
+
def test_get_security_recent_year():
|
|
16
|
+
result = get_security_recent_year(symbol="ddl")
|
|
17
|
+
assert isinstance(result, (list, type(None)))
|
|
18
|
+
|
|
19
|
+
def test_get_session_trades():
|
|
20
|
+
result = get_session_trades(session="1136")
|
|
21
|
+
assert isinstance(result, (list, type(None)))
|
|
22
|
+
|
|
23
|
+
def test_get_security_session_trade():
|
|
24
|
+
result = get_security_session_trade(symbol="ddl", session="1136")
|
|
25
|
+
assert isinstance(result, (dict, type(None)))
|
|
26
|
+
|
|
27
|
+
def test_search_securities():
|
|
28
|
+
result = search_securities(query="ddl")
|
|
29
|
+
assert isinstance(result, list)
|
|
30
|
+
|
|
31
|
+
def test_get_trades_for_year():
|
|
32
|
+
result = get_trades_for_year(symbol="ddl", year="2019")
|
|
33
|
+
assert isinstance(result, (list, type(None)))
|
|
34
|
+
|
|
35
|
+
def test_get_historical_trades():
|
|
36
|
+
result = get_historical_trades(symbol="ddl", start_date="01/06/2020", end_date="01/01/2022")
|
|
37
|
+
assert isinstance(result, (list, type(None)))
|