async-rithmic 1.0.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.
- async_rithmic-1.0.0/LICENSE +21 -0
- async_rithmic-1.0.0/MANIFEST.in +5 -0
- async_rithmic-1.0.0/PKG-INFO +308 -0
- async_rithmic-1.0.0/README.md +280 -0
- async_rithmic-1.0.0/pyproject.toml +3 -0
- async_rithmic-1.0.0/setup.cfg +8 -0
- async_rithmic-1.0.0/setup.py +50 -0
- async_rithmic-1.0.0/src/async_rithmic.egg-info/PKG-INFO +308 -0
- async_rithmic-1.0.0/src/async_rithmic.egg-info/SOURCES.txt +93 -0
- async_rithmic-1.0.0/src/async_rithmic.egg-info/dependency_links.txt +1 -0
- async_rithmic-1.0.0/src/async_rithmic.egg-info/requires.txt +9 -0
- async_rithmic-1.0.0/src/async_rithmic.egg-info/top_level.txt +1 -0
- async_rithmic-1.0.0/src/rithmic/__init__.py +5 -0
- async_rithmic-1.0.0/src/rithmic/certificates/rithmic_ssl_cert_auth_params +34 -0
- async_rithmic-1.0.0/src/rithmic/client.py +104 -0
- async_rithmic-1.0.0/src/rithmic/enums.py +32 -0
- async_rithmic-1.0.0/src/rithmic/event.py +21 -0
- async_rithmic-1.0.0/src/rithmic/logger.py +20 -0
- async_rithmic-1.0.0/src/rithmic/plants/__init__.py +4 -0
- async_rithmic-1.0.0/src/rithmic/plants/base.py +341 -0
- async_rithmic-1.0.0/src/rithmic/plants/history.py +205 -0
- async_rithmic-1.0.0/src/rithmic/plants/order.py +261 -0
- async_rithmic-1.0.0/src/rithmic/plants/pnl.py +77 -0
- async_rithmic-1.0.0/src/rithmic/plants/ticker.py +87 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/__init__.py +13 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/account_pnl_position_update_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/base_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/best_bid_offer_pb2.py +28 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/exchange_order_notification_pb2.py +38 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/instrument_pnl_position_update_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/last_trade_pb2.py +30 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_account_list_pb2.py +28 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_account_rms_info_pb2.py +28 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_bracket_order_pb2.py +42 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_cancel_order_pb2.py +28 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_front_month_contract_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_heartbeat_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_login_info_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_login_pb2.py +28 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_logout_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_market_data_update_pb2.py +30 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_modify_order_pb2.py +34 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_new_order_pb2.py +38 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_pnl_position_snapshot_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_pnl_position_updates_pb2.py +28 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_product_rms_info_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_reference_data_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_rithmic_system_info_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_search_symbols_pb2.py +30 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_show_order_history_detail_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_show_orders_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_subscribe_for_order_updates_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_subscribe_to_bracket_updates_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_tick_bar_replay_pb2.py +34 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_tick_bar_update_pb2.py +32 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_time_bar_replay_pb2.py +32 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_time_bar_update_pb2.py +30 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_trade_routes_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_update_stop_bracket_level_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/request_update_target_bracket_level_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_account_list_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_account_rms_info_pb2.py +30 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_bracket_order_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_cancel_order_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_front_month_contract_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_heartbeat_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_login_info_pb2.py +28 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_login_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_logout_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_market_data_update_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_modify_order_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_new_order_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_pnl_position_snapshot_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_pnl_position_updates_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_product_rms_info_pb2.py +28 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_reference_data_pb2.py +28 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_rithmic_system_info_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_search_symbols_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_show_order_history_detail_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_show_orders_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_subscribe_for_order_updates_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_tick_bar_replay_pb2.py +30 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_tick_bar_update_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_time_bar_replay_pb2.py +28 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_time_bar_update_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_trade_routes_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_update_stop_bracket_level_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/response_update_target_bracket_level_pb2.py +26 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/rithmic_order_notification_pb2.py +38 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/tick_bar_pb2.py +30 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/time_bar_pb2.py +28 -0
- async_rithmic-1.0.0/src/rithmic/protocol_buffers/trade_route_pb2.py +26 -0
- async_rithmic-1.0.0/tests/test_base.py +104 -0
- async_rithmic-1.0.0/tests/test_ticker.py +12 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Mickael Burguet
|
|
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.
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: async_rithmic
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Python API Integration with Rithmic Protocol Buffer API
|
|
5
|
+
Home-page: https://github.com/rundef/pyrithmic
|
|
6
|
+
Author: Mickael Burguet
|
|
7
|
+
Project-URL: Documentation, https://github.com/rundef/pyrithmic
|
|
8
|
+
Project-URL: Bug Reports, https://github.com/rundef/pyrithmic/issues
|
|
9
|
+
Project-URL: Source Code, https://github.com/rundef/pyrithmic
|
|
10
|
+
Keywords: python rithmic
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
21
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
22
|
+
Classifier: Operating System :: OS Independent
|
|
23
|
+
Requires-Python: >=3.8
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Provides-Extra: test
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
|
|
29
|
+
# Python Rithmic API
|
|
30
|
+
|
|
31
|
+
A robust, async-based Python API designed to interface seamlessly with the Rithmic Protocol Buffer API. This package is built to provide an efficient and reliable connection to Rithmic's trading infrastructure, catering to advanced trading strategies and real-time data handling.
|
|
32
|
+
|
|
33
|
+
This was originally a fork of [pyrithmic](https://github.com/jacksonwoody/pyrithmic), but the code has been completely rewritten.
|
|
34
|
+
|
|
35
|
+
## Key Enhancements
|
|
36
|
+
|
|
37
|
+
This repo introduces several key improvements and new features over the original repository, ensuring compatibility with modern Python environments and providing additional functionality:
|
|
38
|
+
|
|
39
|
+
- **Python 3.11+ Compatibility**: Refactored code to ensure smooth operation with the latest Python versions.
|
|
40
|
+
- **System Name Validation**: Implements pre-login validation of system names, as recommended by Rithmic support, with enhanced error handling during the login process.
|
|
41
|
+
- **Account Selection**: Allows users to specify which account to use when calling trading functions, rather than being restricted to the primary account.
|
|
42
|
+
- **STOP Orders**: Exposing STOP orders to users
|
|
43
|
+
- **Best Bid Offer (BBO) Streaming**: Integrates real-time Best Bid Offer tick streaming.
|
|
44
|
+
- **Historical Time Bars + Time Bars Streaming**:
|
|
45
|
+
|
|
46
|
+
The most significant upgrade is the transition to an async architecture, providing superior performance and responsiveness when dealing with real-time trading and market data.
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
pip install git+https://github.com/rundef/pyrithmic.git#egg=pyrithmic
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Market data
|
|
55
|
+
|
|
56
|
+
### Streaming Live Tick Data
|
|
57
|
+
|
|
58
|
+
Here's an example to get the front month contract for ES and stream market data:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
import asyncio
|
|
62
|
+
from rithmic import RithmicClient, Gateway, DataType, LastTradePresenceBits
|
|
63
|
+
|
|
64
|
+
async def callback(data: dict):
|
|
65
|
+
if data["presence_bits"] & LastTradePresenceBits.LAST_TRADE:
|
|
66
|
+
print("received", data)
|
|
67
|
+
|
|
68
|
+
async def main():
|
|
69
|
+
client = RithmicClient(user="", password="", system_name="Rithmic Test", app_name="my_test_app", app_version="1.0", gateway=Gateway.TEST)
|
|
70
|
+
await client.connect()
|
|
71
|
+
|
|
72
|
+
# Request front month contract
|
|
73
|
+
symbol, exchange = "ES", "CME"
|
|
74
|
+
security_code = await client.get_front_month_contract(symbol, exchange)
|
|
75
|
+
|
|
76
|
+
# Stream market data
|
|
77
|
+
print(f"Streaming market data for {security_code}")
|
|
78
|
+
data_type = DataType.LAST_TRADE
|
|
79
|
+
client.on_tick += callback
|
|
80
|
+
await client.subscribe_to_market_data(security_code, exchange, data_type)
|
|
81
|
+
|
|
82
|
+
# Wait 10 seconds, unsubscribe and disconnect
|
|
83
|
+
await asyncio.sleep(10)
|
|
84
|
+
await client.unsubscribe_from_market_data(security_code, exchange, data_type)
|
|
85
|
+
await client.disconnect()
|
|
86
|
+
|
|
87
|
+
asyncio.run(main())
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Streaming Live Time Bars
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
import asyncio
|
|
94
|
+
from rithmic import RithmicClient, Gateway, TimeBarType
|
|
95
|
+
|
|
96
|
+
async def callback(data: dict):
|
|
97
|
+
print("received", data)
|
|
98
|
+
|
|
99
|
+
async def main():
|
|
100
|
+
client = RithmicClient(user="", password="", system_name="Rithmic Test", app_name="my_test_app", app_version="1.0", gateway=Gateway.TEST)
|
|
101
|
+
await client.connect()
|
|
102
|
+
|
|
103
|
+
# Request front month contract
|
|
104
|
+
symbol, exchange = "ES", "CME"
|
|
105
|
+
security_code = await client.get_front_month_contract(symbol, exchange)
|
|
106
|
+
|
|
107
|
+
# Stream market data
|
|
108
|
+
print(f"Streaming market data for {security_code}")
|
|
109
|
+
|
|
110
|
+
client.on_time_bar += callback
|
|
111
|
+
await client.subscribe_to_time_bar_data(security_code, exchange, TimeBarType.SECOND_BAR, 6)
|
|
112
|
+
|
|
113
|
+
# Wait 10 seconds, unsubscribe and disconnect
|
|
114
|
+
await asyncio.sleep(20)
|
|
115
|
+
await client.unsubscribe_from_time_bar_data(security_code, exchange, TimeBarType.SECOND_BAR, 6)
|
|
116
|
+
await client.disconnect()
|
|
117
|
+
|
|
118
|
+
asyncio.run(main())
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Order API
|
|
122
|
+
|
|
123
|
+
#### Placing a Market Order:
|
|
124
|
+
|
|
125
|
+
As a market order will be filled immediately, this script will submit the order and receive a fill straight away:
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
import asyncio
|
|
129
|
+
from datetime import datetime
|
|
130
|
+
from rithmic import RithmicClient, Gateway, OrderType, ExchangeOrderNotificationType, TransactionType
|
|
131
|
+
|
|
132
|
+
async def callback(notification):
|
|
133
|
+
if notification.notify_type == ExchangeOrderNotificationType.FILL:
|
|
134
|
+
print("order filled", notification)
|
|
135
|
+
|
|
136
|
+
async def main():
|
|
137
|
+
client = RithmicClient(user="", password="", system_name="Rithmic Test", app_name="my_test_app", app_version="1.0", gateway=Gateway.TEST)
|
|
138
|
+
await client.connect()
|
|
139
|
+
|
|
140
|
+
# Request front month contract
|
|
141
|
+
symbol, exchange = "ES", "CME"
|
|
142
|
+
security_code = await client.get_front_month_contract(symbol, exchange)
|
|
143
|
+
|
|
144
|
+
# Submit order
|
|
145
|
+
client.on_exchange_order_notification += callback
|
|
146
|
+
|
|
147
|
+
order_id = '{0}_order'.format(datetime.now().strftime('%Y%m%d_%H%M%S'))
|
|
148
|
+
await client.submit_order(
|
|
149
|
+
order_id,
|
|
150
|
+
security_code,
|
|
151
|
+
exchange,
|
|
152
|
+
qty=1,
|
|
153
|
+
order_type=OrderType.MARKET,
|
|
154
|
+
transaction_type=TransactionType.SELL,
|
|
155
|
+
#account_id="ABCD" # Mandatory if you have multiple accounts
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
await asyncio.sleep(1)
|
|
159
|
+
|
|
160
|
+
await client.disconnect()
|
|
161
|
+
|
|
162
|
+
asyncio.run(main())
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
#### Placing a Limit Order and cancelling it
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
import asyncio
|
|
169
|
+
from datetime import datetime
|
|
170
|
+
from rithmic import RithmicClient, Gateway, OrderType, TransactionType
|
|
171
|
+
|
|
172
|
+
async def exchange_order_notification_callback(notification):
|
|
173
|
+
print("exchange order notification", notification)
|
|
174
|
+
|
|
175
|
+
async def main():
|
|
176
|
+
client = RithmicClient(user="", password="", system_name="Rithmic Test", app_name="my_test_app", app_version="1.0", gateway=Gateway.TEST)
|
|
177
|
+
await client.connect()
|
|
178
|
+
|
|
179
|
+
# Request front month contract
|
|
180
|
+
symbol, exchange = "ES", "CME"
|
|
181
|
+
security_code = await client.get_front_month_contract(symbol, exchange)
|
|
182
|
+
|
|
183
|
+
# Submit order
|
|
184
|
+
client.on_exchange_order_notification += exchange_order_notification_callback
|
|
185
|
+
|
|
186
|
+
order_id = '{0}_order'.format(datetime.now().strftime('%Y%m%d_%H%M%S'))
|
|
187
|
+
await client.submit_order(
|
|
188
|
+
order_id,
|
|
189
|
+
security_code,
|
|
190
|
+
exchange,
|
|
191
|
+
qty=1,
|
|
192
|
+
order_type=OrderType.LIMIT,
|
|
193
|
+
transaction_type=TransactionType.BUY,
|
|
194
|
+
price=5300.
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
await asyncio.sleep(1)
|
|
198
|
+
await client.cancel_order(order_id)
|
|
199
|
+
|
|
200
|
+
await asyncio.sleep(1)
|
|
201
|
+
await client.disconnect()
|
|
202
|
+
|
|
203
|
+
asyncio.run(main())
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## History Data API
|
|
207
|
+
|
|
208
|
+
### Fetch Historical Tick Data
|
|
209
|
+
|
|
210
|
+
The following example will fetch historical data, in a streaming fashion:
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
import asyncio
|
|
214
|
+
from datetime import datetime
|
|
215
|
+
from rithmic import RithmicClient, Gateway
|
|
216
|
+
|
|
217
|
+
async def main():
|
|
218
|
+
client = RithmicClient(user="", password="", system_name="Rithmic Test", app_name="my_test_app", app_version="1.0", gateway=Gateway.TEST)
|
|
219
|
+
await client.connect()
|
|
220
|
+
|
|
221
|
+
# Fetch historical tick data
|
|
222
|
+
ticks = await client.get_historical_tick_data(
|
|
223
|
+
"ESZ4",
|
|
224
|
+
"CME",
|
|
225
|
+
datetime(2024, 10, 15, 15, 30),
|
|
226
|
+
datetime(2024, 10, 15, 15, 31),
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
print(f"Received {len(ticks)} ticks")
|
|
230
|
+
print(f"Last tick timestamp: {ticks[-1]['datetime']}")
|
|
231
|
+
|
|
232
|
+
await client.disconnect()
|
|
233
|
+
|
|
234
|
+
asyncio.run(main())
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Fetch Historical Time Bars
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
import asyncio
|
|
241
|
+
from datetime import datetime
|
|
242
|
+
from rithmic import RithmicClient, Gateway, TimeBarType
|
|
243
|
+
|
|
244
|
+
async def main():
|
|
245
|
+
client = RithmicClient(user="", password="", system_name="Rithmic Test", app_name="my_test_app", app_version="1.0", gateway=Gateway.TEST)
|
|
246
|
+
await client.connect()
|
|
247
|
+
|
|
248
|
+
# Fetch historical time bar data
|
|
249
|
+
bars = await client.get_historical_time_bar(
|
|
250
|
+
"ESZ4",
|
|
251
|
+
"CME",
|
|
252
|
+
datetime(2024, 10, 15, 15, 30),
|
|
253
|
+
datetime(2024, 10, 15, 15, 31),
|
|
254
|
+
TimeBarType.SECOND_BAR,
|
|
255
|
+
6
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
print(f"Received {len(bars)} bars")
|
|
259
|
+
print(f"Last bar timestamp: {bars[-1]['datetime']}")
|
|
260
|
+
|
|
261
|
+
await client.disconnect()
|
|
262
|
+
|
|
263
|
+
asyncio.run(main())
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Other methods
|
|
267
|
+
|
|
268
|
+
This code snippet will list your account summary, session orders and positions:
|
|
269
|
+
|
|
270
|
+
```python
|
|
271
|
+
import asyncio
|
|
272
|
+
from rithmic import RithmicClient, Gateway
|
|
273
|
+
|
|
274
|
+
async def main():
|
|
275
|
+
client = RithmicClient(user="", password="", system_name="Rithmic Test", app_name="my_test_app", app_version="1.0", gateway=Gateway.TEST)
|
|
276
|
+
await client.connect()
|
|
277
|
+
|
|
278
|
+
account_id = "MY_ACCOUNT"
|
|
279
|
+
|
|
280
|
+
summary = await client.list_account_summary(account_id=account_id)
|
|
281
|
+
print("Account summary:", summary[0])
|
|
282
|
+
|
|
283
|
+
orders = await client.list_orders(account_id=account_id)
|
|
284
|
+
print("Orders:", orders)
|
|
285
|
+
|
|
286
|
+
positions = await client.list_positions(account_id=account_id)
|
|
287
|
+
print("Positions:", positions)
|
|
288
|
+
|
|
289
|
+
await client.disconnect()
|
|
290
|
+
|
|
291
|
+
asyncio.run(main())
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Testing
|
|
295
|
+
|
|
296
|
+
To execute the tests, use the following command: `make tests`
|
|
297
|
+
|
|
298
|
+
## Unimplemented
|
|
299
|
+
|
|
300
|
+
The following features are currently not available in this package.
|
|
301
|
+
Contributions are welcome!
|
|
302
|
+
If you're interested in adding any of these features, please feel free to submit a Pull Request.
|
|
303
|
+
|
|
304
|
+
- Search Symbols Endpoint
|
|
305
|
+
- Bracket Orders
|
|
306
|
+
- One-Cancels-Other (OCO) Orders
|
|
307
|
+
- Market depth
|
|
308
|
+
- Tick bar historical & live data (Volume, Range or Tick bars)
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# Python Rithmic API
|
|
2
|
+
|
|
3
|
+
A robust, async-based Python API designed to interface seamlessly with the Rithmic Protocol Buffer API. This package is built to provide an efficient and reliable connection to Rithmic's trading infrastructure, catering to advanced trading strategies and real-time data handling.
|
|
4
|
+
|
|
5
|
+
This was originally a fork of [pyrithmic](https://github.com/jacksonwoody/pyrithmic), but the code has been completely rewritten.
|
|
6
|
+
|
|
7
|
+
## Key Enhancements
|
|
8
|
+
|
|
9
|
+
This repo introduces several key improvements and new features over the original repository, ensuring compatibility with modern Python environments and providing additional functionality:
|
|
10
|
+
|
|
11
|
+
- **Python 3.11+ Compatibility**: Refactored code to ensure smooth operation with the latest Python versions.
|
|
12
|
+
- **System Name Validation**: Implements pre-login validation of system names, as recommended by Rithmic support, with enhanced error handling during the login process.
|
|
13
|
+
- **Account Selection**: Allows users to specify which account to use when calling trading functions, rather than being restricted to the primary account.
|
|
14
|
+
- **STOP Orders**: Exposing STOP orders to users
|
|
15
|
+
- **Best Bid Offer (BBO) Streaming**: Integrates real-time Best Bid Offer tick streaming.
|
|
16
|
+
- **Historical Time Bars + Time Bars Streaming**:
|
|
17
|
+
|
|
18
|
+
The most significant upgrade is the transition to an async architecture, providing superior performance and responsiveness when dealing with real-time trading and market data.
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
pip install git+https://github.com/rundef/pyrithmic.git#egg=pyrithmic
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Market data
|
|
27
|
+
|
|
28
|
+
### Streaming Live Tick Data
|
|
29
|
+
|
|
30
|
+
Here's an example to get the front month contract for ES and stream market data:
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
import asyncio
|
|
34
|
+
from rithmic import RithmicClient, Gateway, DataType, LastTradePresenceBits
|
|
35
|
+
|
|
36
|
+
async def callback(data: dict):
|
|
37
|
+
if data["presence_bits"] & LastTradePresenceBits.LAST_TRADE:
|
|
38
|
+
print("received", data)
|
|
39
|
+
|
|
40
|
+
async def main():
|
|
41
|
+
client = RithmicClient(user="", password="", system_name="Rithmic Test", app_name="my_test_app", app_version="1.0", gateway=Gateway.TEST)
|
|
42
|
+
await client.connect()
|
|
43
|
+
|
|
44
|
+
# Request front month contract
|
|
45
|
+
symbol, exchange = "ES", "CME"
|
|
46
|
+
security_code = await client.get_front_month_contract(symbol, exchange)
|
|
47
|
+
|
|
48
|
+
# Stream market data
|
|
49
|
+
print(f"Streaming market data for {security_code}")
|
|
50
|
+
data_type = DataType.LAST_TRADE
|
|
51
|
+
client.on_tick += callback
|
|
52
|
+
await client.subscribe_to_market_data(security_code, exchange, data_type)
|
|
53
|
+
|
|
54
|
+
# Wait 10 seconds, unsubscribe and disconnect
|
|
55
|
+
await asyncio.sleep(10)
|
|
56
|
+
await client.unsubscribe_from_market_data(security_code, exchange, data_type)
|
|
57
|
+
await client.disconnect()
|
|
58
|
+
|
|
59
|
+
asyncio.run(main())
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Streaming Live Time Bars
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
import asyncio
|
|
66
|
+
from rithmic import RithmicClient, Gateway, TimeBarType
|
|
67
|
+
|
|
68
|
+
async def callback(data: dict):
|
|
69
|
+
print("received", data)
|
|
70
|
+
|
|
71
|
+
async def main():
|
|
72
|
+
client = RithmicClient(user="", password="", system_name="Rithmic Test", app_name="my_test_app", app_version="1.0", gateway=Gateway.TEST)
|
|
73
|
+
await client.connect()
|
|
74
|
+
|
|
75
|
+
# Request front month contract
|
|
76
|
+
symbol, exchange = "ES", "CME"
|
|
77
|
+
security_code = await client.get_front_month_contract(symbol, exchange)
|
|
78
|
+
|
|
79
|
+
# Stream market data
|
|
80
|
+
print(f"Streaming market data for {security_code}")
|
|
81
|
+
|
|
82
|
+
client.on_time_bar += callback
|
|
83
|
+
await client.subscribe_to_time_bar_data(security_code, exchange, TimeBarType.SECOND_BAR, 6)
|
|
84
|
+
|
|
85
|
+
# Wait 10 seconds, unsubscribe and disconnect
|
|
86
|
+
await asyncio.sleep(20)
|
|
87
|
+
await client.unsubscribe_from_time_bar_data(security_code, exchange, TimeBarType.SECOND_BAR, 6)
|
|
88
|
+
await client.disconnect()
|
|
89
|
+
|
|
90
|
+
asyncio.run(main())
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Order API
|
|
94
|
+
|
|
95
|
+
#### Placing a Market Order:
|
|
96
|
+
|
|
97
|
+
As a market order will be filled immediately, this script will submit the order and receive a fill straight away:
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
import asyncio
|
|
101
|
+
from datetime import datetime
|
|
102
|
+
from rithmic import RithmicClient, Gateway, OrderType, ExchangeOrderNotificationType, TransactionType
|
|
103
|
+
|
|
104
|
+
async def callback(notification):
|
|
105
|
+
if notification.notify_type == ExchangeOrderNotificationType.FILL:
|
|
106
|
+
print("order filled", notification)
|
|
107
|
+
|
|
108
|
+
async def main():
|
|
109
|
+
client = RithmicClient(user="", password="", system_name="Rithmic Test", app_name="my_test_app", app_version="1.0", gateway=Gateway.TEST)
|
|
110
|
+
await client.connect()
|
|
111
|
+
|
|
112
|
+
# Request front month contract
|
|
113
|
+
symbol, exchange = "ES", "CME"
|
|
114
|
+
security_code = await client.get_front_month_contract(symbol, exchange)
|
|
115
|
+
|
|
116
|
+
# Submit order
|
|
117
|
+
client.on_exchange_order_notification += callback
|
|
118
|
+
|
|
119
|
+
order_id = '{0}_order'.format(datetime.now().strftime('%Y%m%d_%H%M%S'))
|
|
120
|
+
await client.submit_order(
|
|
121
|
+
order_id,
|
|
122
|
+
security_code,
|
|
123
|
+
exchange,
|
|
124
|
+
qty=1,
|
|
125
|
+
order_type=OrderType.MARKET,
|
|
126
|
+
transaction_type=TransactionType.SELL,
|
|
127
|
+
#account_id="ABCD" # Mandatory if you have multiple accounts
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
await asyncio.sleep(1)
|
|
131
|
+
|
|
132
|
+
await client.disconnect()
|
|
133
|
+
|
|
134
|
+
asyncio.run(main())
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
#### Placing a Limit Order and cancelling it
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
import asyncio
|
|
141
|
+
from datetime import datetime
|
|
142
|
+
from rithmic import RithmicClient, Gateway, OrderType, TransactionType
|
|
143
|
+
|
|
144
|
+
async def exchange_order_notification_callback(notification):
|
|
145
|
+
print("exchange order notification", notification)
|
|
146
|
+
|
|
147
|
+
async def main():
|
|
148
|
+
client = RithmicClient(user="", password="", system_name="Rithmic Test", app_name="my_test_app", app_version="1.0", gateway=Gateway.TEST)
|
|
149
|
+
await client.connect()
|
|
150
|
+
|
|
151
|
+
# Request front month contract
|
|
152
|
+
symbol, exchange = "ES", "CME"
|
|
153
|
+
security_code = await client.get_front_month_contract(symbol, exchange)
|
|
154
|
+
|
|
155
|
+
# Submit order
|
|
156
|
+
client.on_exchange_order_notification += exchange_order_notification_callback
|
|
157
|
+
|
|
158
|
+
order_id = '{0}_order'.format(datetime.now().strftime('%Y%m%d_%H%M%S'))
|
|
159
|
+
await client.submit_order(
|
|
160
|
+
order_id,
|
|
161
|
+
security_code,
|
|
162
|
+
exchange,
|
|
163
|
+
qty=1,
|
|
164
|
+
order_type=OrderType.LIMIT,
|
|
165
|
+
transaction_type=TransactionType.BUY,
|
|
166
|
+
price=5300.
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
await asyncio.sleep(1)
|
|
170
|
+
await client.cancel_order(order_id)
|
|
171
|
+
|
|
172
|
+
await asyncio.sleep(1)
|
|
173
|
+
await client.disconnect()
|
|
174
|
+
|
|
175
|
+
asyncio.run(main())
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## History Data API
|
|
179
|
+
|
|
180
|
+
### Fetch Historical Tick Data
|
|
181
|
+
|
|
182
|
+
The following example will fetch historical data, in a streaming fashion:
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
import asyncio
|
|
186
|
+
from datetime import datetime
|
|
187
|
+
from rithmic import RithmicClient, Gateway
|
|
188
|
+
|
|
189
|
+
async def main():
|
|
190
|
+
client = RithmicClient(user="", password="", system_name="Rithmic Test", app_name="my_test_app", app_version="1.0", gateway=Gateway.TEST)
|
|
191
|
+
await client.connect()
|
|
192
|
+
|
|
193
|
+
# Fetch historical tick data
|
|
194
|
+
ticks = await client.get_historical_tick_data(
|
|
195
|
+
"ESZ4",
|
|
196
|
+
"CME",
|
|
197
|
+
datetime(2024, 10, 15, 15, 30),
|
|
198
|
+
datetime(2024, 10, 15, 15, 31),
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
print(f"Received {len(ticks)} ticks")
|
|
202
|
+
print(f"Last tick timestamp: {ticks[-1]['datetime']}")
|
|
203
|
+
|
|
204
|
+
await client.disconnect()
|
|
205
|
+
|
|
206
|
+
asyncio.run(main())
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Fetch Historical Time Bars
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
import asyncio
|
|
213
|
+
from datetime import datetime
|
|
214
|
+
from rithmic import RithmicClient, Gateway, TimeBarType
|
|
215
|
+
|
|
216
|
+
async def main():
|
|
217
|
+
client = RithmicClient(user="", password="", system_name="Rithmic Test", app_name="my_test_app", app_version="1.0", gateway=Gateway.TEST)
|
|
218
|
+
await client.connect()
|
|
219
|
+
|
|
220
|
+
# Fetch historical time bar data
|
|
221
|
+
bars = await client.get_historical_time_bar(
|
|
222
|
+
"ESZ4",
|
|
223
|
+
"CME",
|
|
224
|
+
datetime(2024, 10, 15, 15, 30),
|
|
225
|
+
datetime(2024, 10, 15, 15, 31),
|
|
226
|
+
TimeBarType.SECOND_BAR,
|
|
227
|
+
6
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
print(f"Received {len(bars)} bars")
|
|
231
|
+
print(f"Last bar timestamp: {bars[-1]['datetime']}")
|
|
232
|
+
|
|
233
|
+
await client.disconnect()
|
|
234
|
+
|
|
235
|
+
asyncio.run(main())
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Other methods
|
|
239
|
+
|
|
240
|
+
This code snippet will list your account summary, session orders and positions:
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
import asyncio
|
|
244
|
+
from rithmic import RithmicClient, Gateway
|
|
245
|
+
|
|
246
|
+
async def main():
|
|
247
|
+
client = RithmicClient(user="", password="", system_name="Rithmic Test", app_name="my_test_app", app_version="1.0", gateway=Gateway.TEST)
|
|
248
|
+
await client.connect()
|
|
249
|
+
|
|
250
|
+
account_id = "MY_ACCOUNT"
|
|
251
|
+
|
|
252
|
+
summary = await client.list_account_summary(account_id=account_id)
|
|
253
|
+
print("Account summary:", summary[0])
|
|
254
|
+
|
|
255
|
+
orders = await client.list_orders(account_id=account_id)
|
|
256
|
+
print("Orders:", orders)
|
|
257
|
+
|
|
258
|
+
positions = await client.list_positions(account_id=account_id)
|
|
259
|
+
print("Positions:", positions)
|
|
260
|
+
|
|
261
|
+
await client.disconnect()
|
|
262
|
+
|
|
263
|
+
asyncio.run(main())
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Testing
|
|
267
|
+
|
|
268
|
+
To execute the tests, use the following command: `make tests`
|
|
269
|
+
|
|
270
|
+
## Unimplemented
|
|
271
|
+
|
|
272
|
+
The following features are currently not available in this package.
|
|
273
|
+
Contributions are welcome!
|
|
274
|
+
If you're interested in adding any of these features, please feel free to submit a Pull Request.
|
|
275
|
+
|
|
276
|
+
- Search Symbols Endpoint
|
|
277
|
+
- Bracket Orders
|
|
278
|
+
- One-Cancels-Other (OCO) Orders
|
|
279
|
+
- Market depth
|
|
280
|
+
- Tick bar historical & live data (Volume, Range or Tick bars)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import setuptools
|
|
2
|
+
|
|
3
|
+
with open('README.md', 'r', encoding='utf-8') as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
|
|
6
|
+
setuptools.setup(
|
|
7
|
+
name='async_rithmic',
|
|
8
|
+
version='1.0.0',
|
|
9
|
+
author='Mickael Burguet',
|
|
10
|
+
description='Python API Integration with Rithmic Protocol Buffer API',
|
|
11
|
+
keywords='python rithmic',
|
|
12
|
+
long_description=long_description,
|
|
13
|
+
long_description_content_type='text/markdown',
|
|
14
|
+
url='https://github.com/rundef/pyrithmic',
|
|
15
|
+
project_urls={
|
|
16
|
+
'Documentation': 'https://github.com/rundef/pyrithmic',
|
|
17
|
+
'Bug Reports': 'https://github.com/rundef/pyrithmic/issues',
|
|
18
|
+
'Source Code': 'https://github.com/rundef/pyrithmic',
|
|
19
|
+
# 'Funding': '',
|
|
20
|
+
# 'Say Thanks!': '',
|
|
21
|
+
},
|
|
22
|
+
package_dir={'': 'src'},
|
|
23
|
+
packages=setuptools.find_packages(where='src'),
|
|
24
|
+
include_package_data=True,
|
|
25
|
+
classifiers=[
|
|
26
|
+
# see https://pypi.org/classifiers/
|
|
27
|
+
'Development Status :: 5 - Production/Stable',
|
|
28
|
+
|
|
29
|
+
'Intended Audience :: Developers',
|
|
30
|
+
'Topic :: Software Development :: Build Tools',
|
|
31
|
+
'Programming Language :: Python :: 3',
|
|
32
|
+
'Programming Language :: Python :: 3.8',
|
|
33
|
+
'Programming Language :: Python :: 3.9',
|
|
34
|
+
'Programming Language :: Python :: 3.10',
|
|
35
|
+
'Programming Language :: Python :: 3.11',
|
|
36
|
+
'Programming Language :: Python :: 3.12',
|
|
37
|
+
'Programming Language :: Python :: 3 :: Only',
|
|
38
|
+
'License :: OSI Approved :: MIT License',
|
|
39
|
+
'Operating System :: OS Independent',
|
|
40
|
+
],
|
|
41
|
+
python_requires='>=3.8',
|
|
42
|
+
install_requires=[
|
|
43
|
+
'websockets>=9.0',
|
|
44
|
+
'protobuf==4.25.4',
|
|
45
|
+
],
|
|
46
|
+
extras_require={
|
|
47
|
+
'dev': ['check-manifest'],
|
|
48
|
+
'test': ['coverage', 'pytest'],
|
|
49
|
+
},
|
|
50
|
+
)
|