Skip to content

Commit 32fdc98

Browse files
authored
Merge pull request #125 from drewrice2/master
Websocket PyMongo support
2 parents 2a1db82 + e50e360 commit 32fdc98

File tree

3 files changed

+70
-41
lines changed

3 files changed

+70
-41
lines changed

README.md

Lines changed: 53 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
# gdax-python
2-
The Python client for the [GDAX API](https://docs.gdax.com/) (formerly known as
2+
The Python client for the [GDAX API](https://docs.gdax.com/) (formerly known as
33
the Coinbase Exchange API)
44

55
##### Provided under MIT License by Daniel Paquin.
6-
*Note: this library may be subtly broken or buggy. The code is released under
6+
*Note: this library may be subtly broken or buggy. The code is released under
77
the MIT License – please take the following message to heart:*
8-
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
9-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
10-
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
11-
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
12-
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
8+
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
9+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
10+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
11+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
12+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1313
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1414

1515
## Benefits
1616
- A simple to use python wrapper for both public and authenticated endpoints.
17-
- In about 10 minutes, you could be programmatically trading on one of the
17+
- In about 10 minutes, you could be programmatically trading on one of the
1818
largest Bitcoin exchanges in the *world*!
19-
- Do not worry about handling the nuances of the API with easy-to-use methods
19+
- Do not worry about handling the nuances of the API with easy-to-use methods
2020
for every API endpoint.
21-
- Gain an advantage in the market by getting under the hood of GDAX to learn
21+
- Gain an advantage in the market by getting under the hood of GDAX to learn
2222
what and who is *really* behind every tick.
2323

2424
## Under Development
@@ -27,10 +27,10 @@ what and who is *really* behind every tick.
2727
- FIX API Client **Looking for assistance**
2828

2929
## Getting Started
30-
This README is documentation on the syntax of the python client presented in
30+
This README is documentation on the syntax of the python client presented in
3131
this repository. See function docstrings for full syntax details.
32-
**This API attempts to present a clean interface to GDAX, but in order to use it
33-
to its full potential, you must familiarize yourself with the official GDAX
32+
**This API attempts to present a clean interface to GDAX, but in order to use it
33+
to its full potential, you must familiarize yourself with the official GDAX
3434
documentation.**
3535

3636
- https://docs.gdax.com/
@@ -41,7 +41,7 @@ pip install gdax
4141
```
4242

4343
### Public Client
44-
Only some endpoints in the API are available to everyone. The public endpoints
44+
Only some endpoints in the API are available to everyone. The public endpoints
4545
can be reached using ```PublicClient```
4646

4747
```python
@@ -112,25 +112,25 @@ import gdax
112112
auth_client = gdax.AuthenticatedClient(key, b64secret, passphrase)
113113

114114
# Use the sandbox API (requires a different set of API access credentials)
115-
auth_client = gdax.AuthenticatedClient(key, b64secret, passphrase,
115+
auth_client = gdax.AuthenticatedClient(key, b64secret, passphrase,
116116
api_url="https://api-public.sandbox.gdax.com")
117117
```
118118

119119
### Pagination
120-
Some calls are [paginated](https://docs.gdax.com/#pagination), meaning multiple
121-
calls must be made to receive the full set of data. Each page/request is a list
122-
of dict objects that are then appended to a master list, making it easy to
123-
navigate pages (e.g. ```request[0]``` would return the first page of data in the
124-
example below). *This feature is under consideration for redesign. Please
120+
Some calls are [paginated](https://docs.gdax.com/#pagination), meaning multiple
121+
calls must be made to receive the full set of data. Each page/request is a list
122+
of dict objects that are then appended to a master list, making it easy to
123+
navigate pages (e.g. ```request[0]``` would return the first page of data in the
124+
example below). *This feature is under consideration for redesign. Please
125125
provide feedback if you have issues or suggestions*
126126
```python
127127
request = auth_client.get_fills(limit=100)
128128
request[0] # Page 1 always present
129129
request[1] # Page 2+ present only if the data exists
130130
```
131-
It should be noted that limit does not behave exactly as the official
132-
documentation specifies. If you request a limit and that limit is met,
133-
additional pages will not be returned. This is to ensure speedy response times
131+
It should be noted that limit does not behave exactly as the official
132+
documentation specifies. If you request a limit and that limit is met,
133+
additional pages will not be returned. This is to ensure speedy response times
134134
when less data is preferred.
135135

136136
### AuthenticatedClient Methods
@@ -215,7 +215,7 @@ auth_client.withdraw(withdrawParams)
215215
```
216216

217217
### WebsocketClient
218-
If you would like to receive real-time market updates, you must subscribe to the
218+
If you would like to receive real-time market updates, you must subscribe to the
219219
[websocket feed](https://docs.gdax.com/#websocket-feed).
220220

221221
#### Subscribe to a single product
@@ -231,18 +231,36 @@ wsClient.close()
231231
```python
232232
import gdax
233233
# Paramaters are optional
234-
wsClient = gdax.WebsocketClient(url="wss://ws-feed.gdax.com",
234+
wsClient = gdax.WebsocketClient(url="wss://ws-feed.gdax.com",
235235
products=["BTC-USD", "ETH-USD"])
236236
# Do other stuff...
237237
wsClient.close()
238238
```
239239

240+
### WebsocketClient + Mongodb
241+
The ```WebsocketClient``` now supports data gathering via MongoDB. Given a
242+
MongoDB collection, the ```WebsocketClient``` will stream results directly into
243+
the database collection.
244+
```python
245+
# import PyMongo and connect to a local, running Mongo instance
246+
from pymongo import MongoClient
247+
mongo_client = MongoClient('mongodb://localhost:27017/')
248+
# specify the database and collection
249+
db = mongo_client.cryptocurrency_database
250+
BTC_collection = db.BTC_collection
251+
# instantiate a WebsocketClient instance, with a Mongo collection as a parameter
252+
wsClient = WebsocketClient(url="wss://ws-feed.gdax.com", products="BTC-USD",
253+
mongo_collection=BTC_collection, should_print=False)
254+
wsClient.start()
255+
```
256+
240257
### WebsocketClient Methods
241-
The ```WebsocketClient``` subscribes in a separate thread upon initialization.
242-
There are three methods which you could overwrite (before initialization) so it
243-
can react to the data streaming in. The current client is a template used for
258+
The ```WebsocketClient``` subscribes in a separate thread upon initialization.
259+
There are three methods which you could overwrite (before initialization) so it
260+
can react to the data streaming in. The current client is a template used for
244261
illustration purposes only.
245262

263+
246264
- onOpen - called once, *immediately before* the socket connection is made, this
247265
is where you want to add initial parameters.
248266
- onMessage - called once for every message that arrives and accepts one
@@ -260,7 +278,7 @@ class myWebsocketClient(gdax.WebsocketClient):
260278
def on_message(self, msg):
261279
self.message_count += 1
262280
if 'price' in msg and 'type' in msg:
263-
print ("Message type:", msg["type"],
281+
print ("Message type:", msg["type"],
264282
"\t@ {:.3f}".format(float(msg["price"])))
265283
def on_close(self):
266284
print("-- Goodbye! --")
@@ -273,16 +291,17 @@ while (wsClient.message_count < 500):
273291
time.sleep(1)
274292
wsClient.close()
275293
```
294+
276295
## Testing
277-
A test suite is under development. To run the tests, start in the project
296+
A test suite is under development. To run the tests, start in the project
278297
directory and run
279298
```
280299
python -m pytest
281300
```
282301

283302
### Real-time OrderBook
284-
The ```OrderBook``` subscribes to a websocket and keeps a real-time record of
285-
the orderbook for the product_id input. Please provide your feedback for future
303+
The ```OrderBook``` subscribes to a websocket and keeps a real-time record of
304+
the orderbook for the product_id input. Please provide your feedback for future
286305
improvements.
287306

288307
```python
@@ -295,7 +314,7 @@ order_book.close()
295314

296315
## Change Log
297316
*1.0* **Current PyPI release**
298-
- The first release that is not backwards compatible
317+
- The first release that is not backwards compatible
299318
- Refactored to follow PEP 8 Standards
300319
- Improved Documentation
301320

@@ -310,7 +329,7 @@ order_book.close()
310329
- Added additional API functionality such as cancelAll() and ETH withdrawal.
311330

312331
*0.2.1*
313-
- Allowed ```WebsocketClient``` to operate intuitively and restructured example
332+
- Allowed ```WebsocketClient``` to operate intuitively and restructured example
314333
workflow.
315334

316335
*0.2.0*

gdax/websocket_client.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
#
21
# gdax/WebsocketClient.py
3-
# Daniel Paquin
2+
# original author: Daniel Paquin
3+
# mongo "support" added by Drew Rice
4+
#
45
#
56
# Template object to receive messages from the gdax Websocket Feed
67

@@ -12,10 +13,11 @@
1213
import time
1314
from threading import Thread
1415
from websocket import create_connection, WebSocketConnectionClosedException
15-
16+
from pymongo import MongoClient
1617

1718
class WebsocketClient(object):
18-
def __init__(self, url="wss://ws-feed.gdax.com", products=None, message_type="subscribe", auth=False, api_key="", api_secret="", api_passphrase=""):
19+
def __init__(self, url="wss://ws-feed.gdax.com", products=None, message_type="subscribe",
20+
mongo_collection=None, should_print=True, auth=False, api_key="", api_secret="", api_passphrase=""):
1921
self.url = url
2022
self.products = products
2123
self.type = message_type
@@ -26,6 +28,8 @@ def __init__(self, url="wss://ws-feed.gdax.com", products=None, message_type="su
2628
self.api_key = api_key
2729
self.api_secret = api_secret
2830
self.api_passphrase = api_passphrase
31+
self.should_print = should_print
32+
self.mongo_collection = mongo_collection
2933

3034
def start(self):
3135
def _go():
@@ -93,13 +97,18 @@ def close(self):
9397
pass
9498

9599
def on_open(self):
96-
print("-- Subscribed! --\n")
100+
if self.should_print:
101+
print("-- Subscribed! --\n")
97102

98103
def on_close(self):
99-
print("\n-- Socket Closed --")
104+
if self.should_print:
105+
print("\n-- Socket Closed --")
100106

101107
def on_message(self, msg):
102-
print(msg)
108+
if self.should_print:
109+
print(msg)
110+
if self.mongo_collection: # dump JSON to given mongo collection
111+
self.mongo_collection.insert_one(msg)
103112

104113
def on_error(self, e):
105114
print(e)

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ bintrees==2.0.7
22
requests==2.13.0
33
six==1.10.0
44
websocket-client==0.40.0
5+
pymongo

0 commit comments

Comments
 (0)