alpaca-py-nopandas 0.1.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.
Files changed (62) hide show
  1. alpaca/__init__.py +2 -0
  2. alpaca/broker/__init__.py +8 -0
  3. alpaca/broker/client.py +2360 -0
  4. alpaca/broker/enums.py +528 -0
  5. alpaca/broker/models/__init__.py +7 -0
  6. alpaca/broker/models/accounts.py +347 -0
  7. alpaca/broker/models/cip.py +265 -0
  8. alpaca/broker/models/documents.py +159 -0
  9. alpaca/broker/models/funding.py +114 -0
  10. alpaca/broker/models/journals.py +71 -0
  11. alpaca/broker/models/rebalancing.py +80 -0
  12. alpaca/broker/models/trading.py +13 -0
  13. alpaca/broker/requests.py +1135 -0
  14. alpaca/common/__init__.py +6 -0
  15. alpaca/common/constants.py +13 -0
  16. alpaca/common/enums.py +64 -0
  17. alpaca/common/exceptions.py +47 -0
  18. alpaca/common/models.py +21 -0
  19. alpaca/common/requests.py +82 -0
  20. alpaca/common/rest.py +438 -0
  21. alpaca/common/types.py +7 -0
  22. alpaca/common/utils.py +89 -0
  23. alpaca/data/__init__.py +5 -0
  24. alpaca/data/enums.py +184 -0
  25. alpaca/data/historical/__init__.py +13 -0
  26. alpaca/data/historical/corporate_actions.py +76 -0
  27. alpaca/data/historical/crypto.py +299 -0
  28. alpaca/data/historical/news.py +63 -0
  29. alpaca/data/historical/option.py +230 -0
  30. alpaca/data/historical/screener.py +72 -0
  31. alpaca/data/historical/stock.py +226 -0
  32. alpaca/data/historical/utils.py +30 -0
  33. alpaca/data/live/__init__.py +11 -0
  34. alpaca/data/live/crypto.py +168 -0
  35. alpaca/data/live/news.py +62 -0
  36. alpaca/data/live/option.py +88 -0
  37. alpaca/data/live/stock.py +199 -0
  38. alpaca/data/live/websocket.py +390 -0
  39. alpaca/data/mappings.py +84 -0
  40. alpaca/data/models/__init__.py +7 -0
  41. alpaca/data/models/bars.py +83 -0
  42. alpaca/data/models/base.py +45 -0
  43. alpaca/data/models/corporate_actions.py +309 -0
  44. alpaca/data/models/news.py +90 -0
  45. alpaca/data/models/orderbooks.py +59 -0
  46. alpaca/data/models/quotes.py +78 -0
  47. alpaca/data/models/screener.py +68 -0
  48. alpaca/data/models/snapshots.py +132 -0
  49. alpaca/data/models/trades.py +204 -0
  50. alpaca/data/requests.py +580 -0
  51. alpaca/data/timeframe.py +148 -0
  52. alpaca/py.typed +0 -0
  53. alpaca/trading/__init__.py +5 -0
  54. alpaca/trading/client.py +784 -0
  55. alpaca/trading/enums.py +412 -0
  56. alpaca/trading/models.py +697 -0
  57. alpaca/trading/requests.py +604 -0
  58. alpaca/trading/stream.py +225 -0
  59. alpaca_py_nopandas-0.1.0.dist-info/LICENSE +201 -0
  60. alpaca_py_nopandas-0.1.0.dist-info/METADATA +299 -0
  61. alpaca_py_nopandas-0.1.0.dist-info/RECORD +62 -0
  62. alpaca_py_nopandas-0.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,309 @@
1
+ from datetime import date
2
+ from typing import Dict, List, Optional, Union
3
+
4
+ from alpaca.common.models import ModelWithID as BaseModel
5
+ from alpaca.common.types import RawData
6
+ from alpaca.data.models.base import BaseDataSet, TimeSeriesMixin
7
+
8
+
9
+ class ForwardSplit(BaseModel):
10
+ corporate_action_type: str
11
+ symbol: str
12
+ cusip: str
13
+ new_rate: float
14
+ old_rate: float
15
+ process_date: date
16
+ ex_date: date
17
+ record_date: Optional[date] = None
18
+ payable_date: Optional[date] = None
19
+ due_bill_redemption_date: Optional[date] = None
20
+
21
+
22
+ class ReverseSplit(BaseModel):
23
+ corporate_action_type: str
24
+ symbol: str
25
+ old_cusip: str
26
+ new_cusip: str
27
+ new_rate: float
28
+ old_rate: float
29
+ process_date: date
30
+ ex_date: date
31
+ record_date: Optional[date] = None
32
+ payable_date: Optional[date] = None
33
+
34
+
35
+ class UnitSplit(BaseModel):
36
+ corporate_action_type: str
37
+ old_symbol: str
38
+ old_cusip: str
39
+ old_rate: float
40
+ new_symbol: str
41
+ new_cusip: str
42
+ new_rate: float
43
+ alternate_symbol: str
44
+ alternate_cusip: str
45
+ alternate_rate: float
46
+ process_date: date
47
+ effective_date: date
48
+ payable_date: Optional[date] = None
49
+
50
+
51
+ class StockDividend(BaseModel):
52
+ corporate_action_type: str
53
+ symbol: str
54
+ cusip: str
55
+ rate: float
56
+ process_date: date
57
+ ex_date: date
58
+ record_date: Optional[date] = None
59
+ payable_date: Optional[date] = None
60
+
61
+
62
+ class CashDividend(BaseModel):
63
+ corporate_action_type: str
64
+ symbol: str
65
+ cusip: str
66
+ rate: float
67
+ special: bool
68
+ foreign: bool
69
+ process_date: date
70
+ ex_date: date
71
+ record_date: Optional[date] = None
72
+ payable_date: Optional[date] = None
73
+ due_bill_on_date: Optional[date] = None
74
+ due_bill_off_date: Optional[date] = None
75
+
76
+
77
+ class SpinOff(BaseModel):
78
+ corporate_action_type: str
79
+ source_symbol: str
80
+ source_cusip: str
81
+ source_rate: float
82
+ new_symbol: str
83
+ new_cusip: str
84
+ new_rate: float
85
+ process_date: date
86
+ ex_date: date
87
+ record_date: Optional[date] = None
88
+ payable_date: Optional[date] = None
89
+ due_bill_redemption_date: Optional[date] = None
90
+
91
+
92
+ class CashMerger(BaseModel):
93
+ corporate_action_type: str
94
+ acquirer_symbol: Optional[str] = None
95
+ acquirer_cusip: Optional[str] = None
96
+ acquiree_symbol: str
97
+ acquiree_cusip: str
98
+ rate: float
99
+ process_date: date
100
+ effective_date: date
101
+ payable_date: Optional[date] = None
102
+
103
+
104
+ class StockMerger(BaseModel):
105
+ corporate_action_type: str
106
+ acquirer_symbol: str
107
+ acquirer_cusip: str
108
+ acquirer_rate: float
109
+ acquiree_symbol: str
110
+ acquiree_cusip: str
111
+ acquiree_rate: float
112
+ process_date: date
113
+ effective_date: date
114
+ payable_date: Optional[date] = None
115
+
116
+
117
+ class StockAndCashMerger(BaseModel):
118
+ corporate_action_type: str
119
+ acquirer_symbol: str
120
+ acquirer_cusip: str
121
+ acquirer_rate: float
122
+ acquiree_symbol: str
123
+ acquiree_cusip: str
124
+ acquiree_rate: float
125
+ cash_rate: float
126
+ process_date: date
127
+ effective_date: date
128
+ payable_date: Optional[date] = None
129
+
130
+
131
+ class Redemption(BaseModel):
132
+ corporate_action_type: str
133
+ symbol: str
134
+ cusip: str
135
+ rate: float
136
+ process_date: date
137
+ payable_date: Optional[date] = None
138
+
139
+
140
+ class NameChange(BaseModel):
141
+ corporate_action_type: str
142
+ old_symbol: str
143
+ old_cusip: str
144
+ new_symbol: str
145
+ new_cusip: str
146
+ process_date: date
147
+
148
+
149
+ class WorthlessRemoval(BaseModel):
150
+ corporate_action_type: str
151
+ symbol: str
152
+ cusip: str
153
+ process_date: date
154
+
155
+
156
+ class RightsDistribution(BaseModel):
157
+ corporate_action_type: str
158
+ source_symbol: str
159
+ source_cusip: str
160
+ new_symbol: str
161
+ new_cusip: str
162
+ rate: float
163
+ process_date: date
164
+ ex_date: date
165
+ payable_date: date = None
166
+ record_date: Optional[date] = None
167
+ expiration_date: Optional[date] = None
168
+
169
+
170
+ CorporateAction = Union[
171
+ ForwardSplit,
172
+ ReverseSplit,
173
+ UnitSplit,
174
+ StockDividend,
175
+ CashDividend,
176
+ SpinOff,
177
+ CashMerger,
178
+ StockMerger,
179
+ StockAndCashMerger,
180
+ Redemption,
181
+ NameChange,
182
+ WorthlessRemoval,
183
+ RightsDistribution,
184
+ ]
185
+
186
+
187
+ class CorporateActionsSet(BaseDataSet, TimeSeriesMixin):
188
+ """
189
+ A collection of Corporate actions.
190
+ ref. https://docs.alpaca.markets/reference/corporateactions-1
191
+
192
+ Attributes:
193
+ data (Dict[str, List[CorporateAction]]): The collection of corporate actions.
194
+ """
195
+
196
+ data: Dict[
197
+ str,
198
+ List[CorporateAction],
199
+ ] = {}
200
+
201
+ def __init__(self, raw_data: RawData) -> None:
202
+ """
203
+ Instantiates a CorporateActionsSet - a collection of CorporateAction.
204
+
205
+ Args:
206
+ raw_data (RawData): The raw corporate_actions data received from API
207
+ """
208
+ parsed_corporate_actions: Dict[
209
+ str,
210
+ List[CorporateAction],
211
+ ] = {}
212
+
213
+ if raw_data is None:
214
+ return super().__init__()
215
+
216
+ for corporate_action_type, corporate_actions in raw_data.items():
217
+ if corporate_action_type == "forward_splits":
218
+ parsed_corporate_actions[corporate_action_type] = [
219
+ ForwardSplit(
220
+ corporate_action_type=corporate_action_type, **corporate_action
221
+ )
222
+ for corporate_action in corporate_actions
223
+ ]
224
+ elif corporate_action_type == "reverse_splits":
225
+ parsed_corporate_actions[corporate_action_type] = [
226
+ ReverseSplit(
227
+ corporate_action_type=corporate_action_type, **corporate_action
228
+ )
229
+ for corporate_action in corporate_actions
230
+ ]
231
+ elif corporate_action_type == "unit_splits":
232
+ parsed_corporate_actions[corporate_action_type] = [
233
+ UnitSplit(
234
+ corporate_action_type=corporate_action_type, **corporate_action
235
+ )
236
+ for corporate_action in corporate_actions
237
+ ]
238
+ elif corporate_action_type == "stock_dividends":
239
+ parsed_corporate_actions[corporate_action_type] = [
240
+ StockDividend(
241
+ corporate_action_type=corporate_action_type, **corporate_action
242
+ )
243
+ for corporate_action in corporate_actions
244
+ ]
245
+ elif corporate_action_type == "cash_dividends":
246
+ parsed_corporate_actions[corporate_action_type] = [
247
+ CashDividend(
248
+ corporate_action_type=corporate_action_type, **corporate_action
249
+ )
250
+ for corporate_action in corporate_actions
251
+ ]
252
+ elif corporate_action_type == "spin_offs":
253
+ parsed_corporate_actions[corporate_action_type] = [
254
+ SpinOff(
255
+ corporate_action_type=corporate_action_type, **corporate_action
256
+ )
257
+ for corporate_action in corporate_actions
258
+ ]
259
+ elif corporate_action_type == "cash_mergers":
260
+ parsed_corporate_actions[corporate_action_type] = [
261
+ CashMerger(
262
+ corporate_action_type=corporate_action_type, **corporate_action
263
+ )
264
+ for corporate_action in corporate_actions
265
+ ]
266
+ elif corporate_action_type == "stock_mergers":
267
+ parsed_corporate_actions[corporate_action_type] = [
268
+ StockMerger(
269
+ corporate_action_type=corporate_action_type, **corporate_action
270
+ )
271
+ for corporate_action in corporate_actions
272
+ ]
273
+ elif corporate_action_type == "stock_and_cash_mergers":
274
+ parsed_corporate_actions[corporate_action_type] = [
275
+ StockAndCashMerger(
276
+ corporate_action_type=corporate_action_type, **corporate_action
277
+ )
278
+ for corporate_action in corporate_actions
279
+ ]
280
+ elif corporate_action_type == "redemptions":
281
+ parsed_corporate_actions[corporate_action_type] = [
282
+ Redemption(
283
+ corporate_action_type=corporate_action_type, **corporate_action
284
+ )
285
+ for corporate_action in corporate_actions
286
+ ]
287
+ elif corporate_action_type == "name_changes":
288
+ parsed_corporate_actions[corporate_action_type] = [
289
+ NameChange(
290
+ corporate_action_type=corporate_action_type, **corporate_action
291
+ )
292
+ for corporate_action in corporate_actions
293
+ ]
294
+ elif corporate_action_type == "worthless_removals":
295
+ parsed_corporate_actions[corporate_action_type] = [
296
+ WorthlessRemoval(
297
+ corporate_action_type=corporate_action_type, **corporate_action
298
+ )
299
+ for corporate_action in corporate_actions
300
+ ]
301
+ elif corporate_action_type == "rights_distributions":
302
+ parsed_corporate_actions[corporate_action_type] = [
303
+ RightsDistribution(
304
+ corporate_action_type=corporate_action_type, **corporate_action
305
+ )
306
+ for corporate_action in corporate_actions
307
+ ]
308
+
309
+ super().__init__(data=parsed_corporate_actions)
@@ -0,0 +1,90 @@
1
+ from datetime import datetime
2
+ from typing import List, Optional
3
+
4
+ from alpaca.common.models import ValidateBaseModel as BaseModel
5
+ from alpaca.common.types import RawData
6
+ from alpaca.data import NewsImageSize
7
+ from alpaca.data.models.base import BaseDataSet, TimeSeriesMixin
8
+
9
+
10
+ class NewsImage(BaseModel):
11
+ """
12
+ images (URLs) related to given article
13
+
14
+ Attributes:
15
+ size (NewsImageSize): Possible values for size are thumb, small and large.
16
+ url (str): url to image from news article.
17
+ """
18
+
19
+ size: NewsImageSize
20
+ url: str
21
+
22
+
23
+ class News(BaseModel):
24
+ """
25
+ News article object
26
+
27
+ Attributes:
28
+ id (str): News article ID
29
+ headline (str): Headline or title of the article
30
+ source (str): Source where the news originated from (e.g. Benzinga)
31
+ url (Optional[str]): URL of article (if applicable)
32
+ summary (str): Summary text for the article (may be first sentence of content)
33
+ created_at (datetime): Date article was created (RFC 3339)
34
+ updated_at (datetime): Date article was updated (RFC 3339)
35
+ symbols (List[str]): List of related or mentioned symbols
36
+ content (str): Content of the news article (might contain HTML)
37
+ author (str): Original author of news article
38
+ images (List[NewsImage]): List of images (URLs) related to given article (may be empty)
39
+ """
40
+
41
+ id: int
42
+ headline: str
43
+ source: str
44
+ url: Optional[str]
45
+ summary: str
46
+ created_at: datetime
47
+ updated_at: datetime
48
+ symbols: List[str]
49
+ author: str
50
+ content: str
51
+ images: Optional[List[NewsImage]] = None # only in historical
52
+
53
+ def __init__(self, raw_data: RawData) -> None:
54
+ """Instantiates a news article
55
+
56
+ Args:
57
+ raw_data (RawData): Raw unparsed news data from API.
58
+ """
59
+
60
+ super().__init__(**raw_data)
61
+
62
+
63
+ class NewsSet(BaseDataSet, TimeSeriesMixin):
64
+ """
65
+ A collection of News articles.
66
+
67
+ Attributes:
68
+ data (Dict[str, List[News]]): The collection of News articles.
69
+ next_page_token (Optional[str]): The token to get the next page of data.
70
+ """
71
+
72
+ next_page_token: Optional[str]
73
+
74
+ def __init__(self, raw_data: RawData) -> None:
75
+ """A collection of News articles.
76
+
77
+ Args:
78
+ raw_data (RawData): The collection of raw news data from API.
79
+ """
80
+ parsed_news = {}
81
+ articles = []
82
+
83
+ for article in raw_data.get("news", []):
84
+ news = News(raw_data=article)
85
+ articles.append(news)
86
+
87
+ parsed_news["news"] = articles
88
+ next_page_token = raw_data.get("next_page_token")
89
+
90
+ super().__init__(data=parsed_news, next_page_token=next_page_token)
@@ -0,0 +1,59 @@
1
+ from datetime import datetime
2
+ from typing import List
3
+
4
+ from pydantic import Field, TypeAdapter
5
+
6
+ from alpaca.common.models import ValidateBaseModel as BaseModel
7
+ from alpaca.common.types import RawData
8
+ from alpaca.data.mappings import ORDERBOOK_MAPPING
9
+
10
+
11
+ class OrderbookQuote(BaseModel):
12
+ """A single bid or ask quote in the orderbook"""
13
+
14
+ # using field aliases for easy parsing
15
+ price: float = Field(alias="p")
16
+ size: float = Field(alias="s")
17
+
18
+
19
+ class Orderbook(BaseModel):
20
+ """Level 2 ask/bid pair orderbook data.
21
+
22
+ Attributes:
23
+ symbol (str): The ticker identifier for the security whose data forms the orderbook.
24
+ timestamp (datetime): The time of submission of the orderbook.
25
+ bids (List[OrderbookQuote]): The list of bid quotes for the orderbook
26
+ asks (List[OrderbookQuote]): The list of ask quotes for the orderbook
27
+ reset (bool): if true, the orderbook message contains the whole server side orderbook.
28
+ This indicates to the client that they should reset their orderbook.
29
+ Typically sent as the first message after subscription.
30
+ """
31
+
32
+ symbol: str
33
+ timestamp: datetime
34
+ bids: List[OrderbookQuote]
35
+ asks: List[OrderbookQuote]
36
+ reset: bool = False
37
+
38
+ def __init__(self, symbol: str, raw_data: RawData) -> None:
39
+ """Instantiates an Orderbook.
40
+
41
+ Args:
42
+ symbol (str): The security identifier for the orderbook
43
+ raw_data (RawData): The orderbook data as received by API
44
+ """
45
+
46
+ mapped_book = {
47
+ ORDERBOOK_MAPPING.get(key): val
48
+ for key, val in raw_data.items()
49
+ if key in ORDERBOOK_MAPPING
50
+ }
51
+
52
+ mapped_book["bids"] = TypeAdapter(List[OrderbookQuote]).validate_python(
53
+ mapped_book["bids"]
54
+ )
55
+ mapped_book["asks"] = TypeAdapter(List[OrderbookQuote]).validate_python(
56
+ mapped_book["asks"]
57
+ )
58
+
59
+ super().__init__(symbol=symbol, **mapped_book)
@@ -0,0 +1,78 @@
1
+ from datetime import datetime
2
+ from typing import Dict, List, Optional, Union
3
+
4
+ from alpaca.common.models import ValidateBaseModel as BaseModel
5
+ from alpaca.common.types import RawData
6
+ from alpaca.data.enums import Exchange
7
+ from alpaca.data.mappings import QUOTE_MAPPING
8
+ from alpaca.data.models.base import BaseDataSet, TimeSeriesMixin
9
+
10
+
11
+ class Quote(BaseModel):
12
+ """Level 1 ask/bid pair quote data. Contains information about size and origin exchange.
13
+
14
+ Attributes:
15
+ symbol (str): The ticker identifier for the security whose data forms the quote.
16
+ timestamp (datetime): The time of submission of the quote.
17
+ bid_price (float): The bidding price of the quote.
18
+ bid_size (float): The size of the quote bid.
19
+ bid_exchange (Optional[Union[str, Exchange]]): The exchange the quote bid originates. Defaults to None.
20
+ ask_price (float): The asking price of the quote.
21
+ ask_size (float): The size of the quote ask.
22
+ ask_exchange (Optional[Union[str, Exchange]]): The exchange the quote ask originates. Defaults to None.
23
+ conditions (Optional[Union[List[str], str]]): The quote conditions. Defaults to None.
24
+ tape (Optional[str]): The quote tape. Defaults to None.
25
+ """
26
+
27
+ symbol: str
28
+ timestamp: datetime
29
+ bid_price: float
30
+ bid_size: float
31
+ bid_exchange: Optional[Union[str, Exchange]] = None
32
+ ask_price: float
33
+ ask_size: float
34
+ ask_exchange: Optional[Union[str, Exchange]] = None
35
+ conditions: Optional[Union[List[str], str]] = None
36
+ tape: Optional[str] = None
37
+
38
+ def __init__(self, symbol: str, raw_data: RawData) -> None:
39
+ """Instantiates a Quote
40
+
41
+ Args:
42
+ symbol (str): The security identifier for the quote
43
+ raw_data (RawData): The quote data as received by API
44
+ """
45
+
46
+ mapped_quote = {
47
+ QUOTE_MAPPING.get(key): val
48
+ for key, val in raw_data.items()
49
+ if key in QUOTE_MAPPING
50
+ }
51
+
52
+ super().__init__(symbol=symbol, **mapped_quote)
53
+
54
+
55
+ class QuoteSet(BaseDataSet, TimeSeriesMixin):
56
+ """A collection of Quotes.
57
+
58
+ Attributes:
59
+ data (Dict[str, List[Quote]]): The collection of Quotes keyed by symbol.
60
+ """
61
+
62
+ data: Dict[str, List[Quote]] = {}
63
+
64
+ def __init__(self, raw_data: RawData) -> None:
65
+ """Instantiates a QuoteSet.
66
+
67
+ Args:
68
+ raw_data (RawData): The raw quote data received from API keyed by symbol
69
+ """
70
+ parsed_quotes = {}
71
+
72
+ if raw_data is not None:
73
+ for symbol, quotes in raw_data.items():
74
+ parsed_quotes[symbol] = [
75
+ Quote(symbol, quote) for quote in quotes if quote is not None
76
+ ]
77
+
78
+ super().__init__(data=parsed_quotes)
@@ -0,0 +1,68 @@
1
+ from datetime import datetime
2
+ from typing import List
3
+
4
+ from alpaca.common.models import ValidateBaseModel as BaseModel
5
+ from alpaca.data.enums import MarketType
6
+
7
+
8
+ class ActiveStock(BaseModel):
9
+ """
10
+ Represent one asset that was a most active on the most actives endpoint.
11
+
12
+ Attributes:
13
+ symbol (str): Symbol of market moving asset.
14
+ volume (float): Cumulative volume for the current trading day.
15
+ trade_count (float): Cumulative trade count for the current trading day.
16
+ """
17
+
18
+ symbol: str
19
+ volume: float
20
+ trade_count: float
21
+
22
+
23
+ class MostActives(BaseModel):
24
+ """
25
+ Represent the response model for the MostActives endpoint.
26
+ Attributes:
27
+ most_actives (List[ActiveStock]): list of top N most active symbols.
28
+ last_updated (datetime):
29
+ Time when the MostActives were last computed.
30
+ Formatted as a RFC 3339 formatted datetime with nanosecond precision.
31
+ """
32
+
33
+ most_actives: List[ActiveStock]
34
+ last_updated: datetime
35
+
36
+
37
+ class Mover(BaseModel):
38
+ """
39
+ Represent one asset that was a top mover on the top market movers endpoint.
40
+ Attributes:
41
+ symbol (str): Symbol of market moving asset.
42
+ percent_change (float): Percentage difference change for the day.
43
+ change (float): Difference in change for the day.
44
+ price (float): Current price of market moving asset.
45
+ """
46
+
47
+ symbol: str
48
+ percent_change: float
49
+ change: float
50
+ price: float
51
+
52
+
53
+ class Movers(BaseModel):
54
+ """
55
+ Represent the response model for the top market movers endpoint.
56
+ Attributes:
57
+ gainers (List[Mover]): list of top N gainers.
58
+ losers (List[Mover]): list of top N losers.
59
+ market_type (MarketType): Market type (stocks or crypto).
60
+ last_updated (datetime):
61
+ Time when the movers were last computed.
62
+ Formatted as a RFC 3339 formatted datetime with nanosecond precision.
63
+ """
64
+
65
+ gainers: List[Mover]
66
+ losers: List[Mover]
67
+ market_type: MarketType
68
+ last_updated: datetime