rtbnext 1.0.0__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.
- rtbnext/__init__.py +26 -0
- rtbnext/_version.py +7 -0
- rtbnext/core/cache.py +102 -0
- rtbnext/core/http_client.py +153 -0
- rtbnext/core/loader.py +173 -0
- rtbnext/core/parser.py +84 -0
- rtbnext/core/rate_limiter.py +86 -0
- rtbnext/defaults.py +26 -0
- rtbnext/endpoint/base.py +80 -0
- rtbnext/endpoint/filter.py +112 -0
- rtbnext/endpoint/list.py +85 -0
- rtbnext/endpoint/mover.py +33 -0
- rtbnext/endpoint/profile.py +158 -0
- rtbnext/endpoint/stats.py +156 -0
- rtbnext/endpoint/system.py +25 -0
- rtbnext/py.typed +0 -0
- rtbnext/resource/base.py +206 -0
- rtbnext/resource/collectable.py +201 -0
- rtbnext/resource/collection.py +313 -0
- rtbnext/resource/dateable.py +59 -0
- rtbnext/resource/indexable.py +91 -0
- rtbnext/resource/series.py +266 -0
- rtbnext/rtbnext.py +107 -0
- rtbnext/schema/assets.py +101 -0
- rtbnext/schema/filter.py +35 -0
- rtbnext/schema/generic.py +105 -0
- rtbnext/schema/list.py +64 -0
- rtbnext/schema/mover.py +40 -0
- rtbnext/schema/profile.py +137 -0
- rtbnext/schema/stats.py +133 -0
- rtbnext/schema/system.py +15 -0
- rtbnext/utils.py +36 -0
- rtbnext-1.0.0.dist-info/METADATA +161 -0
- rtbnext-1.0.0.dist-info/RECORD +36 -0
- rtbnext-1.0.0.dist-info/WHEEL +4 -0
- rtbnext-1.0.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Time Series Resource
|
|
3
|
+
|
|
4
|
+
Implements the resource wrapper for time-series endpoints.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from collections import defaultdict
|
|
10
|
+
from datetime import date as date_type
|
|
11
|
+
from statistics import mean, median
|
|
12
|
+
from typing import Callable, Generic, Literal, TypedDict, TypeVar, cast
|
|
13
|
+
|
|
14
|
+
from rtbnext.core.loader import ResourceStateLoader
|
|
15
|
+
from rtbnext.core.parser import ParserFn
|
|
16
|
+
from rtbnext.resource.base import Resource
|
|
17
|
+
from rtbnext.resource.collection import DateCollectionBase
|
|
18
|
+
|
|
19
|
+
TimePoint = TypedDict( "TimePoint", { "date": str } )
|
|
20
|
+
type TimeSeriesRow = tuple
|
|
21
|
+
|
|
22
|
+
AggregateValue = TypedDict( "AggregateValue", {
|
|
23
|
+
"first": float,
|
|
24
|
+
"last": float,
|
|
25
|
+
"min": float,
|
|
26
|
+
"max": float,
|
|
27
|
+
"avg": float,
|
|
28
|
+
"median": float,
|
|
29
|
+
"sum": float
|
|
30
|
+
} )
|
|
31
|
+
|
|
32
|
+
AggregateRange = TypedDict( "AggregateRange", {
|
|
33
|
+
"from": str,
|
|
34
|
+
"to": str
|
|
35
|
+
} )
|
|
36
|
+
|
|
37
|
+
AggregatePoint = TypedDict( "AggregatePoint", {
|
|
38
|
+
"date": str,
|
|
39
|
+
"label": str,
|
|
40
|
+
"range": AggregateRange
|
|
41
|
+
} )
|
|
42
|
+
|
|
43
|
+
A = TypeVar( "A", bound= AggregatePoint )
|
|
44
|
+
D = TypeVar( "D", bound= list[ TimeSeriesRow ] )
|
|
45
|
+
R = TypeVar( "R", bound= TimePoint )
|
|
46
|
+
|
|
47
|
+
type AggregatePeriod = Literal[ "week", "month", "quarter", "year" ]
|
|
48
|
+
type NumberCallback[ R ] = Callable[ [ R ], int | float ]
|
|
49
|
+
type PointFn[ D, R ] = Callable[ [ D ], R ]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class TimeSeriesCollection( DateCollectionBase[ R, R ], Generic[ R, A ] ):
|
|
53
|
+
"""
|
|
54
|
+
Collection wrapper for time-series resources.
|
|
55
|
+
|
|
56
|
+
This class is the base for CSV resource collections, providing methods
|
|
57
|
+
to access dated data points, aggregate them and get statistical values
|
|
58
|
+
like min, max, median etc.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
def _numbers( self, callback: NumberCallback | None = None ) -> list[ float ]:
|
|
62
|
+
"""Returns numeric values from points."""
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
[ float( callback( point ) ) for point in self ]
|
|
66
|
+
if callback is not None else
|
|
67
|
+
[
|
|
68
|
+
float( value ) for point in self for key, value in point.items()
|
|
69
|
+
if key != "date" and isinstance( value, ( int, float ) )
|
|
70
|
+
]
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
def _period( self, date: str, period: AggregatePeriod ) -> str:
|
|
74
|
+
"""Creates an aggregation key from a date."""
|
|
75
|
+
|
|
76
|
+
year, month, day = map( int, date.split( "-" ) )
|
|
77
|
+
|
|
78
|
+
if period == "year":
|
|
79
|
+
return str( year )
|
|
80
|
+
|
|
81
|
+
if period == "quarter":
|
|
82
|
+
return f"{ year }-Q{ ( month - 1 ) // 3 + 1 }"
|
|
83
|
+
|
|
84
|
+
if period == "month":
|
|
85
|
+
return f"{ year }-{month:02d}"
|
|
86
|
+
|
|
87
|
+
if period == "week":
|
|
88
|
+
iso_year, iso_week, _ = date_type( year, month, day ).isocalendar()
|
|
89
|
+
return f"{ iso_year }-W{iso_week:02d}"
|
|
90
|
+
|
|
91
|
+
raise ValueError( f"Invalid aggregate period: { period }" )
|
|
92
|
+
|
|
93
|
+
def _aggregate( self, points: list[ R ], label: str | None = None ) -> A:
|
|
94
|
+
"""Aggregates a group of points."""
|
|
95
|
+
|
|
96
|
+
sorted_points = sorted( points, key= lambda point: point[ "date" ] )
|
|
97
|
+
|
|
98
|
+
result: dict[ str, object ] = {
|
|
99
|
+
"date": sorted_points[ -1 ][ "date" ],
|
|
100
|
+
"label": label or sorted_points[ -1 ][ "date" ],
|
|
101
|
+
"range": {
|
|
102
|
+
"from": sorted_points[ 0 ][ "date" ],
|
|
103
|
+
"to": sorted_points[ -1 ][ "date" ]
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
keys = sorted_points[ 0 ].keys()
|
|
108
|
+
|
|
109
|
+
for key in keys:
|
|
110
|
+
if key == "date":
|
|
111
|
+
continue
|
|
112
|
+
|
|
113
|
+
values = [
|
|
114
|
+
float( point[ key ] ) for point in sorted_points
|
|
115
|
+
if isinstance( point.get( key ), ( int, float ) )
|
|
116
|
+
]
|
|
117
|
+
|
|
118
|
+
if not values:
|
|
119
|
+
continue
|
|
120
|
+
|
|
121
|
+
result[ key ] = {
|
|
122
|
+
"first": values[ 0 ],
|
|
123
|
+
"last": values[ -1 ],
|
|
124
|
+
"min": min( values ),
|
|
125
|
+
"max": max( values ),
|
|
126
|
+
"avg": float( mean( values ) ),
|
|
127
|
+
"median": float( median( values ) ),
|
|
128
|
+
"sum": sum( values )
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return cast( A, result )
|
|
132
|
+
|
|
133
|
+
def _aggregated_series( self, points: list[ A ] ) -> TimeSeriesCollection[ A, A ]:
|
|
134
|
+
"""Returns a time series collection of aggregated points."""
|
|
135
|
+
|
|
136
|
+
return TimeSeriesCollection(
|
|
137
|
+
points,
|
|
138
|
+
factory= lambda item: item,
|
|
139
|
+
date= lambda item: item[ "date" ]
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
@property
|
|
143
|
+
def points( self ) -> list[ R ]:
|
|
144
|
+
"""Returns all time series points."""
|
|
145
|
+
|
|
146
|
+
return self._items
|
|
147
|
+
|
|
148
|
+
def min( self, callback: NumberCallback[ R ] | None = None ) -> float:
|
|
149
|
+
"""Returns the minimum value."""
|
|
150
|
+
|
|
151
|
+
return min( self._numbers( callback ) )
|
|
152
|
+
|
|
153
|
+
def max( self, callback: NumberCallback[ R ] | None = None ) -> float:
|
|
154
|
+
"""Returns the maximum value."""
|
|
155
|
+
|
|
156
|
+
return max( self._numbers( callback ) )
|
|
157
|
+
|
|
158
|
+
def sum( self, callback: NumberCallback[ R ] | None = None ) -> float:
|
|
159
|
+
"""Returns the sum of values."""
|
|
160
|
+
|
|
161
|
+
return sum( self._numbers( callback ) )
|
|
162
|
+
|
|
163
|
+
def avg( self, callback: NumberCallback[ R ] | None = None ) -> float:
|
|
164
|
+
"""Returns the average value."""
|
|
165
|
+
|
|
166
|
+
return float( mean( self._numbers( callback ) ) )
|
|
167
|
+
|
|
168
|
+
def median( self, callback: NumberCallback[ R ] | None = None ) -> float:
|
|
169
|
+
"""Returns the median value."""
|
|
170
|
+
|
|
171
|
+
return float( median( self._numbers( callback ) ) )
|
|
172
|
+
|
|
173
|
+
@property
|
|
174
|
+
def labels( self ) -> list[ str ]:
|
|
175
|
+
"""Returns the date labels."""
|
|
176
|
+
|
|
177
|
+
return [ point[ "date" ] for point in self ]
|
|
178
|
+
|
|
179
|
+
@property
|
|
180
|
+
def columns( self ) -> dict[ str, list[ object ] ]:
|
|
181
|
+
"""Returns the values grouped by column."""
|
|
182
|
+
|
|
183
|
+
result: dict[ str, list[ object ] ] = {}
|
|
184
|
+
|
|
185
|
+
for point in self:
|
|
186
|
+
for key, value in point.items():
|
|
187
|
+
result.setdefault( key, [] ).append( value )
|
|
188
|
+
|
|
189
|
+
return result
|
|
190
|
+
|
|
191
|
+
def values( self, callback: NumberCallback ) -> list[ int | float ]:
|
|
192
|
+
"""Returns the mapped numeric values."""
|
|
193
|
+
|
|
194
|
+
return [ callback( point ) for point in self ]
|
|
195
|
+
|
|
196
|
+
def column( self, key: str ) -> list[ object ]:
|
|
197
|
+
"""Returns all values of a column."""
|
|
198
|
+
|
|
199
|
+
return [ point[ key ] for point in self ]
|
|
200
|
+
|
|
201
|
+
def aggregate(
|
|
202
|
+
self,
|
|
203
|
+
period: AggregatePeriod | Callable[ [ R ], str ]
|
|
204
|
+
) -> TimeSeriesCollection[ A, A ]:
|
|
205
|
+
"""Aggregates points by period."""
|
|
206
|
+
|
|
207
|
+
groups: dict[ str, list[ R ] ] = defaultdict( list )
|
|
208
|
+
|
|
209
|
+
for point in self:
|
|
210
|
+
groups[ (
|
|
211
|
+
period( point ) if callable( period )
|
|
212
|
+
else self._period( point[ "date" ], period )
|
|
213
|
+
) ].append( point )
|
|
214
|
+
|
|
215
|
+
return self._aggregated_series( [
|
|
216
|
+
self._aggregate( group, label )
|
|
217
|
+
for label, group in groups.items()
|
|
218
|
+
] )
|
|
219
|
+
|
|
220
|
+
def buckets( self, count: int ) -> TimeSeriesCollection[ A, A ]:
|
|
221
|
+
"""Splits points into equally sized buckets."""
|
|
222
|
+
|
|
223
|
+
if count >= self.count:
|
|
224
|
+
return self._aggregated_series( [
|
|
225
|
+
self._aggregate( [ point ], f"{ index + 1 }/{ self.count }" )
|
|
226
|
+
for index, point in enumerate( self )
|
|
227
|
+
] )
|
|
228
|
+
|
|
229
|
+
size, points = self.count / count, self.items
|
|
230
|
+
result: list[ A ] = []
|
|
231
|
+
|
|
232
|
+
for index in range( count ):
|
|
233
|
+
start, end = int( index * size ), int( ( index + 1 ) * size )
|
|
234
|
+
result.append( self._aggregate( points[ start : end ], f"{ index + 1 }/{ count }" ) )
|
|
235
|
+
|
|
236
|
+
return self._aggregated_series( result )
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class TimeSeriesResource( Resource[ D ], Generic[ D, R, A ] ):
|
|
240
|
+
"""
|
|
241
|
+
Resource wrapper for time-series endpoints.
|
|
242
|
+
|
|
243
|
+
This class converts raw CSV rows into typed time-series points and
|
|
244
|
+
exposes them through a time-series collection.
|
|
245
|
+
"""
|
|
246
|
+
|
|
247
|
+
def __init__(
|
|
248
|
+
self, path: str, loader: ResourceStateLoader, parser: ParserFn[ D ], *,
|
|
249
|
+
point: PointFn[ TimeSeriesRow, R ]
|
|
250
|
+
) -> None:
|
|
251
|
+
super().__init__( path, loader, parser )
|
|
252
|
+
self._point = point
|
|
253
|
+
|
|
254
|
+
def _collect_points( self, rows: D ) -> TimeSeriesCollection[ R, A ]:
|
|
255
|
+
"""Creates a time-series collection from raw rows."""
|
|
256
|
+
|
|
257
|
+
return TimeSeriesCollection(
|
|
258
|
+
[ self._point( row ) for row in reversed( rows ) ],
|
|
259
|
+
factory= lambda item: item,
|
|
260
|
+
date= lambda point: point[ "date" ]
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
async def series( self ) -> TimeSeriesCollection[ R, A ]:
|
|
264
|
+
"""Returns the parsed time-series data as a typed collection."""
|
|
265
|
+
|
|
266
|
+
return await self._transform( self._collect_points )
|
rtbnext/rtbnext.py
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""
|
|
2
|
+
RTBNext
|
|
3
|
+
|
|
4
|
+
Implements the main entry point class for the RTBNext Python SDK exposing
|
|
5
|
+
all API endpoints.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from typing import Self
|
|
12
|
+
|
|
13
|
+
from rtbnext.core.http_client import ClientIdentity, HttpClient
|
|
14
|
+
from rtbnext.core.loader import CacheMode, CacheType, ResourceStateLoader
|
|
15
|
+
from rtbnext.defaults import (
|
|
16
|
+
DEFAULT_API_URL, DEFAULT_CACHE_MODE, DEFAULT_CACHE_TYPE, DEFAULT_TIMEOUT
|
|
17
|
+
)
|
|
18
|
+
from rtbnext.endpoint.filter import FilterEndpoint
|
|
19
|
+
from rtbnext.endpoint.list import ListEndpoint
|
|
20
|
+
from rtbnext.endpoint.mover import MoverEndpoint
|
|
21
|
+
from rtbnext.endpoint.profile import ProfileEndpoint
|
|
22
|
+
from rtbnext.endpoint.stats import StatsEndpoint
|
|
23
|
+
from rtbnext.endpoint.system import SystemEndpoint
|
|
24
|
+
from rtbnext.resource.base import ResourcePool
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass( slots= True, kw_only= True )
|
|
28
|
+
class Endpoints:
|
|
29
|
+
"""Endpoints available in the RTBNext SDK."""
|
|
30
|
+
|
|
31
|
+
profile: ProfileEndpoint
|
|
32
|
+
list: ListEndpoint
|
|
33
|
+
mover: MoverEndpoint
|
|
34
|
+
filter: FilterEndpoint
|
|
35
|
+
stats: StatsEndpoint
|
|
36
|
+
system: SystemEndpoint
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class RTBNext:
|
|
40
|
+
"""
|
|
41
|
+
Main entry point of the RTBNext SDK.
|
|
42
|
+
|
|
43
|
+
Provides access to all RTBNext API endpoints through a single client
|
|
44
|
+
instance while internally managing HTTP communication, resource loading,
|
|
45
|
+
caching, and endpoint initialization.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
def __init__(
|
|
49
|
+
self, client: ClientIdentity, *,
|
|
50
|
+
base_url: str = DEFAULT_API_URL,
|
|
51
|
+
timeout: float = DEFAULT_TIMEOUT,
|
|
52
|
+
cache: CacheType = DEFAULT_CACHE_TYPE,
|
|
53
|
+
mode: CacheMode = DEFAULT_CACHE_MODE
|
|
54
|
+
) -> None:
|
|
55
|
+
self._client = HttpClient( client= client, base_url= base_url, timeout= timeout )
|
|
56
|
+
self._loader = ResourceStateLoader( client= self._client, cache= cache, mode= mode )
|
|
57
|
+
self._pool = ResourcePool()
|
|
58
|
+
|
|
59
|
+
endpoints = Endpoints.__new__( Endpoints )
|
|
60
|
+
args = ( self._loader, self._pool, endpoints )
|
|
61
|
+
|
|
62
|
+
self.profile = endpoints.profile = ProfileEndpoint( *args )
|
|
63
|
+
self.list = endpoints.list = ListEndpoint( *args )
|
|
64
|
+
self.mover = endpoints.mover = MoverEndpoint( *args )
|
|
65
|
+
self.filter = endpoints.filter = FilterEndpoint( *args )
|
|
66
|
+
self.stats = endpoints.stats = StatsEndpoint( *args )
|
|
67
|
+
self.system = endpoints.system = SystemEndpoint( *args )
|
|
68
|
+
|
|
69
|
+
self.endpoints = endpoints
|
|
70
|
+
|
|
71
|
+
async def __aenter__( self ) -> Self:
|
|
72
|
+
return self
|
|
73
|
+
|
|
74
|
+
async def __aexit__( self, *_ ) -> None:
|
|
75
|
+
await self.close()
|
|
76
|
+
|
|
77
|
+
async def close( self ) -> None:
|
|
78
|
+
"""Closes the underlying HTTP client and release network resources."""
|
|
79
|
+
|
|
80
|
+
await self._loader.aclose()
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def rtbnext(
|
|
84
|
+
client: ClientIdentity, *,
|
|
85
|
+
base_url: str = DEFAULT_API_URL,
|
|
86
|
+
timeout: float = DEFAULT_TIMEOUT,
|
|
87
|
+
cache: CacheType = DEFAULT_CACHE_TYPE,
|
|
88
|
+
mode: CacheMode = DEFAULT_CACHE_MODE
|
|
89
|
+
) -> RTBNext:
|
|
90
|
+
"""
|
|
91
|
+
Creates a new RTBNext SDK instance.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
client: Client identity information.
|
|
95
|
+
base_url: RTBNext API base URL.
|
|
96
|
+
timeout: HTTP request timeout.
|
|
97
|
+
cache: Cache implementation.
|
|
98
|
+
mode: Cache mode.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
A configured RTBNext SDK instance.
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
return RTBNext(
|
|
105
|
+
client, base_url= base_url, timeout= timeout,
|
|
106
|
+
cache= cache, mode= mode
|
|
107
|
+
)
|
rtbnext/schema/assets.py
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Assets
|
|
3
|
+
|
|
4
|
+
Declares shared types for assets, net worth, rankings, performance metrics,
|
|
5
|
+
and historical financial data.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Literal, NotRequired, TypedDict
|
|
9
|
+
|
|
10
|
+
from rtbnext.schema.generic import AssetType, ChangeFlag
|
|
11
|
+
|
|
12
|
+
type ReturnsPeriod = Literal[
|
|
13
|
+
"week", "month", "quarter", "halfYear", "year", "twoYear", "fiveYear"
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
ChangeItem = TypedDict( "ChangeItem", {
|
|
17
|
+
"value": float,
|
|
18
|
+
"percent": float
|
|
19
|
+
} )
|
|
20
|
+
|
|
21
|
+
AssetInfo = TypedDict( "AssetInfo", {
|
|
22
|
+
"exchange": str,
|
|
23
|
+
"ticker": str,
|
|
24
|
+
"shares": NotRequired[ float ],
|
|
25
|
+
"price": float,
|
|
26
|
+
"currency": str,
|
|
27
|
+
"exRate": float
|
|
28
|
+
} )
|
|
29
|
+
|
|
30
|
+
Asset = TypedDict( "Asset", {
|
|
31
|
+
"type": AssetType,
|
|
32
|
+
"label": str,
|
|
33
|
+
"value": NotRequired[ float ],
|
|
34
|
+
"info": NotRequired[ AssetInfo ]
|
|
35
|
+
} )
|
|
36
|
+
|
|
37
|
+
DataPoint = TypedDict( "DataPoint", {
|
|
38
|
+
"date": str,
|
|
39
|
+
"networth": float,
|
|
40
|
+
"rank": NotRequired[ int ]
|
|
41
|
+
} )
|
|
42
|
+
|
|
43
|
+
Extrema = TypedDict( "Extrema", {
|
|
44
|
+
"high": NotRequired[ DataPoint ],
|
|
45
|
+
"low": NotRequired[ DataPoint ]
|
|
46
|
+
} )
|
|
47
|
+
|
|
48
|
+
type Returns = dict[ ReturnsPeriod, ChangeItem ]
|
|
49
|
+
|
|
50
|
+
Performance = TypedDict( "Performance", {
|
|
51
|
+
"extrema": NotRequired[ Extrema ],
|
|
52
|
+
"returns": NotRequired[ Returns ]
|
|
53
|
+
} )
|
|
54
|
+
|
|
55
|
+
RankingHistoryItem = TypedDict( "RankingHistoryItem", {
|
|
56
|
+
"date": str,
|
|
57
|
+
"rank": NotRequired[ int ],
|
|
58
|
+
"networth": NotRequired[ float ],
|
|
59
|
+
"prev": NotRequired[ str ],
|
|
60
|
+
"next": NotRequired[ str ]
|
|
61
|
+
} )
|
|
62
|
+
|
|
63
|
+
Ranking = TypedDict( "Ranking", {
|
|
64
|
+
"list": str,
|
|
65
|
+
"name": str,
|
|
66
|
+
"date": str,
|
|
67
|
+
"rank": NotRequired[ int ],
|
|
68
|
+
"networth": NotRequired[ float ],
|
|
69
|
+
"prev": NotRequired[ str ],
|
|
70
|
+
"next": NotRequired[ str ],
|
|
71
|
+
"history": NotRequired[ list[ RankingHistoryItem ] ]
|
|
72
|
+
} )
|
|
73
|
+
|
|
74
|
+
Realtime = TypedDict( "Realtime", {
|
|
75
|
+
"date": str,
|
|
76
|
+
"rank": NotRequired[ int ],
|
|
77
|
+
"networth": NotRequired[ float ],
|
|
78
|
+
"prev": NotRequired[ str ],
|
|
79
|
+
"next": NotRequired[ str ],
|
|
80
|
+
"today": NotRequired[ ChangeItem ],
|
|
81
|
+
"ytd": NotRequired[ ChangeItem ]
|
|
82
|
+
} )
|
|
83
|
+
|
|
84
|
+
AnnualRecord = TypedDict( "AnnualRecord", {
|
|
85
|
+
"first": int | float,
|
|
86
|
+
"last": int | float,
|
|
87
|
+
"diff": int | float,
|
|
88
|
+
"flag": ChangeFlag,
|
|
89
|
+
"mean": float,
|
|
90
|
+
"median": float,
|
|
91
|
+
"max": int | float,
|
|
92
|
+
"min": int | float,
|
|
93
|
+
"range": int | float,
|
|
94
|
+
"stdDev": float
|
|
95
|
+
} )
|
|
96
|
+
|
|
97
|
+
Annual = TypedDict( "Annual", {
|
|
98
|
+
"year": int,
|
|
99
|
+
"rank": NotRequired[ AnnualRecord ],
|
|
100
|
+
"networth": NotRequired[ AnnualRecord ]
|
|
101
|
+
} )
|
rtbnext/schema/filter.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Filter
|
|
3
|
+
|
|
4
|
+
Declares filter entries, documents and the index.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any, TypedDict
|
|
8
|
+
|
|
9
|
+
from rtbnext.schema.generic import (
|
|
10
|
+
AgeGroup, FilterSpecial, Gender, Industry, MaritalStatus, MetaData
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
FilterItem = TypedDict( "FilterItem", {
|
|
14
|
+
"uri": str,
|
|
15
|
+
"name": str,
|
|
16
|
+
"value": Any
|
|
17
|
+
} )
|
|
18
|
+
|
|
19
|
+
Filter = TypedDict( "Filter", {
|
|
20
|
+
"$metadata": MetaData,
|
|
21
|
+
"count": int,
|
|
22
|
+
"items": list[ FilterItem ]
|
|
23
|
+
} )
|
|
24
|
+
|
|
25
|
+
FilterIndex = TypedDict( "FilterIndex", {
|
|
26
|
+
"$metadata": MetaData,
|
|
27
|
+
"industry": list[ Industry ],
|
|
28
|
+
"citizenship": list[ str ],
|
|
29
|
+
"country": list[ str ],
|
|
30
|
+
"state": list[ str ],
|
|
31
|
+
"gender": list[ Gender ],
|
|
32
|
+
"age": list[ AgeGroup ],
|
|
33
|
+
"maritalStatus": list[ MaritalStatus ],
|
|
34
|
+
"special": list[ FilterSpecial ]
|
|
35
|
+
} )
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Literals & Generics
|
|
3
|
+
|
|
4
|
+
Declares literals and generic types.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Literal, NotRequired, TypedDict
|
|
8
|
+
|
|
9
|
+
type Industry = Literal[
|
|
10
|
+
"automotive", "diversified", "energy", "engineering", "finance", "foodstuff",
|
|
11
|
+
"gambling", "healthcare", "logistics", "manufacturing", "media", "mining",
|
|
12
|
+
"property", "retail", "service", "sports", "technology", "telecom"
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
type AgeGroup = Literal[ "30", "40", "50", "60", "70", "80", "90" ]
|
|
16
|
+
type Gender = Literal[ "m", "f", "d" ]
|
|
17
|
+
type MaritalStatus = Literal[
|
|
18
|
+
"single", "relationship", "married", "remarried", "engaged", "separated",
|
|
19
|
+
"divorced", "widowed"
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
type SelfMadeRank = Literal[ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" ]
|
|
23
|
+
|
|
24
|
+
type RelationType = Literal[ "person", "organization", "place", "unknown" ]
|
|
25
|
+
type AssetType = Literal[ "public", "private", "misc" ]
|
|
26
|
+
type ChangeFlag = Literal[ "up", "down", "unchanged", "new", "returned", "dropoff", "unknown" ]
|
|
27
|
+
|
|
28
|
+
type ChildrenGroup = Literal[ "none", "one", "two", "three", "four", "5-to-10", "over-10" ]
|
|
29
|
+
type Percentile = Literal[ "10th", "25th", "50th", "75th", "90th", "95th", "99th" ]
|
|
30
|
+
type WealthSpread = Literal[ "1", "2", "5", "10", "20", "50", "100", "200", "500", "1000" ]
|
|
31
|
+
|
|
32
|
+
type FilterSpecial = Literal[ "deceased", "dropOff", "family", "selfMade" ]
|
|
33
|
+
type FilterGroup = Literal[
|
|
34
|
+
"industry", "citizenship", "country", "state", "gender", "age", "maritalStatus",
|
|
35
|
+
"special"
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
type Service = Literal[ "profile", "list", "mover", "filter", "stats", "system" ]
|
|
39
|
+
type StatusFlag = Literal[ "healthy", "degraded", "maintenance", "outage", "unknown" ]
|
|
40
|
+
type ProfileStatusFlag = Literal[ "healthy", "invalid", "missing", "unknown" ]
|
|
41
|
+
|
|
42
|
+
MetaData = TypedDict( "MetaData", {
|
|
43
|
+
"schemaVersion": Literal[ "2" ],
|
|
44
|
+
"generator": str,
|
|
45
|
+
"lastModified": str
|
|
46
|
+
} )
|
|
47
|
+
|
|
48
|
+
DateIndex = TypedDict( "DateIndex", {
|
|
49
|
+
"$metadata": MetaData,
|
|
50
|
+
"dates": list[ str ],
|
|
51
|
+
"latest": NotRequired[ str ]
|
|
52
|
+
} )
|
|
53
|
+
|
|
54
|
+
Location = TypedDict( "Location", {
|
|
55
|
+
"country": str,
|
|
56
|
+
"state": NotRequired[ str ],
|
|
57
|
+
"city": NotRequired[ str ]
|
|
58
|
+
} )
|
|
59
|
+
|
|
60
|
+
Education = TypedDict( "Education", {
|
|
61
|
+
"school": str,
|
|
62
|
+
"degree": NotRequired[ str ]
|
|
63
|
+
} )
|
|
64
|
+
|
|
65
|
+
Organization = TypedDict( "Organization", {
|
|
66
|
+
"name": str,
|
|
67
|
+
"title": NotRequired[ str ]
|
|
68
|
+
} )
|
|
69
|
+
|
|
70
|
+
SelfMade = TypedDict( "SelfMade", {
|
|
71
|
+
"type": NotRequired[ str ],
|
|
72
|
+
"is": bool,
|
|
73
|
+
"rank": NotRequired[ SelfMadeRank ]
|
|
74
|
+
} )
|
|
75
|
+
|
|
76
|
+
Relation = TypedDict( "Relation", {
|
|
77
|
+
"type": RelationType,
|
|
78
|
+
"name": str,
|
|
79
|
+
"relation": NotRequired[ str ],
|
|
80
|
+
"uri": NotRequired[ str ]
|
|
81
|
+
} )
|
|
82
|
+
|
|
83
|
+
Image = TypedDict( "Image", {
|
|
84
|
+
"url": str,
|
|
85
|
+
"credits": str,
|
|
86
|
+
"file": str,
|
|
87
|
+
"thumb": NotRequired[ str ],
|
|
88
|
+
"caption": NotRequired[ str ],
|
|
89
|
+
"desc": NotRequired[ str ],
|
|
90
|
+
"date": NotRequired[ str ]
|
|
91
|
+
} )
|
|
92
|
+
|
|
93
|
+
Wiki = TypedDict( "Wiki", {
|
|
94
|
+
"uri": str,
|
|
95
|
+
"pageId": int,
|
|
96
|
+
"refId": int,
|
|
97
|
+
"confidence": float,
|
|
98
|
+
"name": str,
|
|
99
|
+
"lastModified": str,
|
|
100
|
+
"summary": list[ str ],
|
|
101
|
+
"sortKey": NotRequired[ str ],
|
|
102
|
+
"wikidata": NotRequired[ str ],
|
|
103
|
+
"desc": NotRequired[ str ],
|
|
104
|
+
"image": NotRequired[ Image ]
|
|
105
|
+
} )
|
rtbnext/schema/list.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""
|
|
2
|
+
List
|
|
3
|
+
|
|
4
|
+
Declares types for ranking lists and snapshots.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import NotRequired, TypedDict
|
|
8
|
+
|
|
9
|
+
from rtbnext.schema.assets import ChangeItem
|
|
10
|
+
from rtbnext.schema.generic import ChangeFlag, Gender, Industry, MetaData, SelfMadeRank
|
|
11
|
+
|
|
12
|
+
ListIndexItem = TypedDict( "ListIndexItem", {
|
|
13
|
+
"uri": str,
|
|
14
|
+
"name": str,
|
|
15
|
+
"text": str,
|
|
16
|
+
"shortName": str,
|
|
17
|
+
"desc": str,
|
|
18
|
+
"columns": list[ str ],
|
|
19
|
+
"filters": list[ str ]
|
|
20
|
+
} )
|
|
21
|
+
|
|
22
|
+
ListIndex = TypedDict( "ListIndex", {
|
|
23
|
+
"$metadata": MetaData,
|
|
24
|
+
"count": int,
|
|
25
|
+
"items": list[ ListIndexItem ]
|
|
26
|
+
} )
|
|
27
|
+
|
|
28
|
+
ListItem = TypedDict( "ListItem", {
|
|
29
|
+
"uri": str,
|
|
30
|
+
"sourceUri": str,
|
|
31
|
+
"name": str,
|
|
32
|
+
"rank": int,
|
|
33
|
+
"networth": NotRequired[ float ],
|
|
34
|
+
"industry": NotRequired[ Industry ],
|
|
35
|
+
"source": NotRequired[ list[ str ] ],
|
|
36
|
+
"gender": NotRequired[ Gender ],
|
|
37
|
+
"age": NotRequired[ int ],
|
|
38
|
+
"citizenship": NotRequired[ str ],
|
|
39
|
+
"flag": NotRequired[ ChangeFlag ],
|
|
40
|
+
"rankDiff": NotRequired[ int ],
|
|
41
|
+
"selfMadeRank": NotRequired[ SelfMadeRank ],
|
|
42
|
+
"philanthropyScore": NotRequired[ int ],
|
|
43
|
+
"today": NotRequired[ ChangeItem ],
|
|
44
|
+
"ytd": NotRequired[ ChangeItem ]
|
|
45
|
+
} )
|
|
46
|
+
|
|
47
|
+
ListStats = TypedDict( "ListStats", {
|
|
48
|
+
"date": str,
|
|
49
|
+
"count": int,
|
|
50
|
+
"total": float,
|
|
51
|
+
"woman": int,
|
|
52
|
+
"quota": float,
|
|
53
|
+
"today": NotRequired[ ChangeItem ],
|
|
54
|
+
"ytd": NotRequired[ ChangeItem ]
|
|
55
|
+
} )
|
|
56
|
+
|
|
57
|
+
List = TypedDict( "List", {
|
|
58
|
+
"$metadata": MetaData,
|
|
59
|
+
"uri": str,
|
|
60
|
+
"date": str,
|
|
61
|
+
"count": int,
|
|
62
|
+
"items": list[ ListItem ],
|
|
63
|
+
"stats": ListStats
|
|
64
|
+
} )
|