Core Library: Common¶
Utilities shared across services.
Context¶
context ¶
Secure context derivation for encrypting and decrypting provider secrets.
DerivedContext ¶
DerivedContext(
aesgcm: AESGCM, nonce: bytes, ciphertext: bytes
)
Decryption helper holding derived AES context and encrypted payload.
Store encryption artifacts for later retrieval.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
aesgcm
|
AESGCM
|
Derived cipher context. |
required |
nonce
|
bytes
|
Nonce used during encryption. |
required |
ciphertext
|
bytes
|
Encrypted payload. |
required |
Source code in quasar/lib/common/context.py
72 73 74 75 76 77 78 79 80 81 82 | |
get ¶
get(key: str) -> str
Return a secret field from the encrypted JSON payload.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
Key inside the decrypted JSON blob. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
Retrieved value for the requested key. |
Raises:
| Type | Description |
|---|---|
KeyError
|
If the key is missing. |
ValueError
|
If the payload cannot be parsed. |
Source code in quasar/lib/common/context.py
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | |
SystemContext ¶
Singleton that loads the system context and derives per-provider keys.
__new__ ¶
__new__(*args, **kwargs)
Create or return the singleton instance.
Source code in quasar/lib/common/context.py
18 19 20 21 22 23 24 25 26 27 | |
create_context_data ¶
create_context_data(
hash: bytes, data: bytes
) -> tuple[bytes, bytes]
Encrypt data with a derived AES context.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
hash
|
bytes
|
Salt/input used to derive a unique key. |
required |
data
|
bytes
|
Plaintext payload to encrypt. |
required |
Returns:
| Type | Description |
|---|---|
tuple[bytes, bytes]
|
tuple[bytes, bytes]: Tuple of (nonce, ciphertext). |
Source code in quasar/lib/common/context.py
53 54 55 56 57 58 59 60 61 62 63 64 65 66 | |
get_derived_context ¶
get_derived_context(hash: bytes) -> AESGCM | None
Derive an AESGCM key using the system context and provided hash.
Source code in quasar/lib/common/context.py
42 43 44 45 46 47 48 49 50 51 | |
Database handler¶
database_handler ¶
Shared database handler with pooled connection lifecycle helpers.
DatabaseHandler ¶
DatabaseHandler(
dsn: str | None = None, pool: Optional[Pool] = None
)
Bases: ABC
Manage asyncpg pools and expose a unified interface.
Configure the handler with either a DSN or an existing pool.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dsn
|
str | None
|
Database connection string used to create a pool. |
None
|
pool
|
Pool | None
|
Pre-existing pool to reuse. |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If neither |
Source code in quasar/lib/common/database_handler.py
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | |
close_pool
async
¶
close_pool() -> None
Close the owned pool.
Source code in quasar/lib/common/database_handler.py
54 55 56 57 | |
init_pool
async
¶
init_pool() -> None
Create the asyncpg pool if this handler owns it.
Source code in quasar/lib/common/database_handler.py
49 50 51 52 | |
API handler¶
api_handler ¶
Shared FastAPI handler base with lifecycle helpers.
APIHandler ¶
APIHandler(api_host: str = '0.0.0.0', api_port: int = 8080)
Bases: ABC
Serve a FastAPI application and manage its lifecycle.
Configure and create the FastAPI application.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
api_host
|
str
|
Host interface to bind to. |
'0.0.0.0'
|
api_port
|
int
|
Port number to expose the API on. |
8080
|
Source code in quasar/lib/common/api_handler.py
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | |
start_api_server
async
¶
start_api_server() -> None
Start the internal API server.
Source code in quasar/lib/common/api_handler.py
65 66 67 68 69 70 71 72 73 74 75 76 77 78 | |
stop_api_server
async
¶
stop_api_server() -> None
Stop the internal API server and await shutdown.
Source code in quasar/lib/common/api_handler.py
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | |
Secret store¶
secret_store ¶
Secret store that can read from local files or AWS SSM.
SecretStore ¶
SecretStore(
mode: str = "auto", aws_region: str | None = None
)
Load provider secrets from disk or AWS Parameter Store.
Create a secret store.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mode
|
str
|
One of |
'auto'
|
aws_region
|
str | None
|
AWS region to use when |
None
|
Source code in quasar/lib/common/secret_store.py
21 22 23 24 25 26 27 28 29 30 31 | |
get
async
¶
get(provider: str) -> dict
Return provider secrets using local files or AWS depending on mode.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
provider
|
str
|
Provider key to load secrets for. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
dict |
dict
|
Provider secrets payload. |
Raises:
| Type | Description |
|---|---|
SecretsFileNotFoundError
|
When auto mode cannot locate a secrets file. |
Source code in quasar/lib/common/secret_store.py
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | |
load_cfg_from_file ¶
load_cfg_from_file(provider: str, file: Path) -> dict
Read provider config from a JSON secrets file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
provider
|
str
|
Provider key inside the secrets file. |
required |
file
|
Path
|
Path to the JSON file. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
dict |
dict
|
Provider configuration. |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If the file is missing. |
KeyError
|
If the provider key is not present. |
Source code in quasar/lib/common/secret_store.py
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | |
SecretsFileNotFoundError ¶
Bases: Exception
Raised when no secrets file can be located in auto mode.
Offset cron¶
offset_cron ¶
Cron trigger variant that applies a positive or negative offset.
OffsetCronTrigger ¶
OffsetCronTrigger(offset_seconds: int = 0, **kwargs: Any)
Bases: CronTrigger
CronTrigger that fires at a specified offset from the base schedule.
Initialize the trigger with an offset.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
offset_seconds
|
int
|
Seconds to shift the scheduled time. Negative values schedule before the base trigger. |
0
|
**kwargs
|
Any
|
Standard |
{}
|
Source code in quasar/lib/common/offset_cron.py
11 12 13 14 15 16 17 18 19 20 21 | |
from_crontab
classmethod
¶
from_crontab(
expr: str,
offset_seconds: int = 0,
timezone: tzinfo | str | None = None,
) -> OffsetCronTrigger
Create an OffsetCronTrigger from a crontab expression.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
expr
|
str
|
Standard crontab fields |
required |
offset_seconds
|
int
|
Seconds to offset the trigger time; can be negative. |
0
|
timezone
|
tzinfo | str | None
|
Time zone for calculations; defaults to scheduler timezone. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
OffsetCronTrigger |
OffsetCronTrigger
|
Configured trigger instance. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the crontab expression does not contain 5 fields. |
Source code in quasar/lib/common/offset_cron.py
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | |
get_next_fire_time ¶
get_next_fire_time(previous_fire_time, now)
Return the next fire time adjusted by the configured offset.
Source code in quasar/lib/common/offset_cron.py
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | |
Trading calendar¶
calendar ¶
Trading calendar utility wrapping exchange_calendars with custom Forex support.
This module provides a unified interface for checking market status across various exchanges and asset classes. Assets without an exchange (e.g., cryptocurrencies) default to 'always open' behavior.
ForexCalendar ¶
Bases: ExchangeCalendar
24/5 Trading Calendar for Forex (Standard Sunday 5pm ET to Friday 5pm ET).
close_times
property
¶
close_times
Return the daily close times.
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
Tuple containing the daily close time. |
name
property
¶
name: str
Return the calendar name.
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The calendar name ("XFX"). |
open_times
property
¶
open_times
Return the daily open times.
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
Tuple containing the daily open time. |
regular_holidays
property
¶
regular_holidays
Return the list of regular holidays.
Returns:
| Name | Type | Description |
|---|---|---|
None |
Forex markets handled via weekmask for now. |
tz
property
¶
tz
Return the timezone for the calendar.
Returns:
| Type | Description |
|---|---|
|
datetime.tzinfo: The America/New_York timezone. |
weekmask
property
¶
weekmask: str
Return the weekmask defining active days (Mon-Fri + Sun).
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The weekmask "1111101". |
TradingCalendar ¶
Wrapper for exchange_calendars providing a unified interface for Quasar.
has_sessions_in_range
classmethod
¶
has_sessions_in_range(
mic: str, start: date, end: date
) -> bool
Check if there were any trading sessions between two dates.
Used primarily by Historical Data providers to determine if a "gap" in data contains any actual sessions worth pulling.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mic
|
str
|
The Market Identifier Code (ISO 10383). |
required |
start
|
date
|
Start of the range (inclusive). |
required |
end
|
date
|
End of the range (inclusive). |
required |
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if at least one session occurred, False otherwise. Defaults to True if MIC is unknown. |
Source code in quasar/lib/common/calendar.py
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | |
is_open_now
classmethod
¶
is_open_now(mic: str) -> bool
Check if the market for the given MIC is currently open.
Used primarily by Live Data providers to determine if a connection should be established.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mic
|
str
|
The Market Identifier Code (ISO 10383). |
required |
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if the market is open, False otherwise. Defaults to True if MIC is unknown. |
Source code in quasar/lib/common/calendar.py
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | |
is_session
classmethod
¶
is_session(mic: str, day: date) -> bool
Check if the given date was a valid trading session for the MIC.
Used primarily by Historical Data providers to determine if a data pull should be executed for a specific date.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mic
|
str
|
The Market Identifier Code (ISO 10383). |
required |
day
|
date
|
The date to check. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if the date was a session, False otherwise. Defaults to True if MIC is unknown. |
Source code in quasar/lib/common/calendar.py
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | |
Enum guard¶
enum_guard ¶
Optional runtime guard to ensure enums match database lookup tables.
validate_enums
async
¶
validate_enums(pool: Pool, strict: bool = False) -> None
Compare generated enums with DB lookup tables.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pool
|
Pool
|
The asyncpg connection pool to use for DB checks. |
required |
strict
|
bool
|
If True, raise a RuntimeError if mismatches are found. If False, only log warnings. Defaults to False. |
False
|
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If |
Source code in quasar/lib/common/enum_guard.py
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | |