Skip to content

Commit b1a1191

Browse files
committed
Initial commit
0 parents  commit b1a1191

File tree

15 files changed

+2585
-0
lines changed

15 files changed

+2585
-0
lines changed

.eastwood

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1555019149563

.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
pom.xml*
2+
*jar
3+
/lib/
4+
/classes/
5+
/target/
6+
.nrepl-port
7+
.lein-repl-history
8+
.lein-deps-sum
9+
.lein-failures
10+
*.swp
11+
autodoc/**
12+
*.DS_Store
13+
dev-fixtures

ISSUE_TEMPLATE/bug_report.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
name: Bug report
3+
about: Create a report to help us improve
4+
title: "[BUG] - ..."
5+
labels: bug
6+
assignees: ''
7+
8+
---
9+
10+
### Description
11+
- Provide a good description of the issue
12+
13+
### Steps to Reproduce
14+
- Provide a description of the bug
15+
- Any relevant information on how you go to this state
16+
- Bonus points for a video recording (either from you or from FullStory)
17+
18+
### Logs
19+
- Provide relevant & unbiased information (logs, market movements, Robinhood screenshots, etc) that might help diagnose the issue
20+
21+
### Business Impact / Severity Level
22+
- Provide a severity level of this bug
23+
24+
- 1 - Critical Impact / System Down
25+
- 2 - Significant Impact
26+
- 3 - Normal/Minor Impact
27+
- 4 - Low/Informational
28+
29+
### Acceptance Criteria
30+
- [ ] These are subtasks for this bug

ISSUE_TEMPLATE/feature-request.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
name: Feature request
3+
about: Suggest an idea for this project
4+
title: "[FEATURE] - ..."
5+
labels: enhancement
6+
assignees: ''
7+
8+
---
9+
10+
#### Description
11+
- This section is a brief description of the feature ("As a X, I should be able to Y, so that I can Z")
12+
- Make sure to link this to the appropriate Epic
13+
14+
#### Acceptance Criteria
15+
- [ ] These are the subtasks for this feature
16+
17+
#### Design
18+
- Please attach any Figma links or design assets

README.md

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
# robinhood.clj
2+
3+
A lightweight clojure wrapper for the [Robinhood Web API](https://github.com/sanko/Robinhood/).
4+
5+
All use cases must follow the [Robinhood TOS](
6+
https://brokerage-static.s3.amazonaws.com/assets/robinhood/legal/Robinhood%20Terms%20and%20Conditions.pdf). For example, you may not use this client to scrape Robinhood data for display on your own website, among other things. Read the TOS.
7+
8+
### Authenticating with environment variables
9+
10+
You'll have to set up your machine's environment variables before hitting any endpoints that require authentication.
11+
12+
You can get your device token by monitoring your browser's login request to robinhood. Open chrome developer tools > navigate to network tab > login to Robinhood in browser > search network tab for the `token/` request > view request payload > copy device_token.
13+
14+
```
15+
export ROBINHOOD_USER="..."
16+
export ROBINHOOD_PASS="..."
17+
export ROBINHOOD_DEVICE_TOKEN="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
18+
;Don't forget to restart any running repls
19+
```
20+
21+
After adding the above environment variables, `lein test` should run without any failures.
22+
23+
Be sure not to commit any of the above information to this repo for the world to see! If you do, change your passwords immediately and enable 2FA.
24+
25+
### Caution
26+
27+
At the time of writing, the Robinhood Web API lacks official documentation. Hence, working with this wrapper (at least for now) demands some reverse engineering of the robinhood UI. @Sanko's unofficial docs at [Robinhood Web API](https://github.com/sanko/Robinhood/) are good but not 100% up to date.
28+
29+
I've added some notes on how I'm scraping by in the `Dev` section at the bottom.
30+
31+
### REPL Usage
32+
33+
Cd into robinhood.clj and run `lein repl` in order to follow along:
34+
35+
Login:
36+
``` clojure
37+
(use 'robinhood.clj.auth)
38+
39+
# Get a robinhood client
40+
(def rc' (authed-client))
41+
42+
;; output:
43+
:robinhood{:access-token "xxxxxxxxx"}
44+
```
45+
46+
Fetch Quotes:
47+
``` clojure
48+
(use 'robinhood.clj.auth)
49+
(use 'robinhood.clj.client)
50+
51+
(quotes (authed-client) {:symbols "AAPL,MSFT"})
52+
53+
;; output:
54+
(#:robinhood.quote{:updated-at "2021-01-16T01:00:00Z",
55+
:instrument
56+
"https://api.robinhood.com/instruments/450dfc6d-5510-4d40-abfb-f633b7d9be3e/",
57+
:bid-price 126.41,
58+
:last-trade-price-source "consolidated",
59+
:symbol "AAPL",
60+
:last-trade-price 127.14,
61+
:ask-price 500.0,
62+
:bid-size 21,
63+
:ask-size 596,
64+
:last-extended-hours-trade-price 126.82,
65+
:previous-close 128.91,
66+
:has-traded true,
67+
:trading-halted false,
68+
:adjusted-previous-close 128.91,
69+
:previous-close-date "2021-01-14"}
70+
#:robinhood.quote{:updated-at "2021-01-16T01:00:00Z",
71+
:instrument
72+
"https://api.robinhood.com/instruments/50810c35-d215-4866-9758-0ada4ac79ffa/",
73+
:bid-price 210.91,
74+
:last-trade-price-source "consolidated",
75+
:symbol "MSFT",
76+
:last-trade-price 212.65,
77+
:ask-price 215.86,
78+
:bid-size 30,
79+
:ask-size 200,
80+
:last-extended-hours-trade-price 212.55,
81+
:previous-close 213.02,
82+
:has-traded true,
83+
:trading-halted false,
84+
:adjusted-previous-close 213.02,
85+
:previous-close-date "2021-01-14"})
86+
```
87+
88+
89+
90+
See call options on a ticker:
91+
``` clojure
92+
(use 'robinhood.clj.auth)
93+
(use 'robinhood.clj.client)
94+
95+
(take 2 ;for brevity
96+
(get-option-chain-prices (authed-client) {:symbols "EAF"} "call"))
97+
98+
;; output (you'll see some logs of all the requests made):
99+
({:robinhood.option-contract/bid-size 101,
100+
:robinhood.option-contract/break-even-price 11.1,
101+
:robinhood.option-contract/high-price 3.7,
102+
:robinhood.option-contract/low-price 3.4,
103+
:robinhood.option-date-chain/id
104+
"f7e8bfbe-26a1-4300-952b-038d21f332ae",
105+
:robinhood.option-contract/instrument
106+
"https://api.robinhood.com/options/instruments/f7e8bfbe-26a1-4300-952b-038d21f332ae/",
107+
:robinhood.option-date-chain/tradability "tradable",
108+
:robinhood.option-contract/last-trade-size 10,
109+
:robinhood.option-contract/high-fill-rate-buy-price 3.74,
110+
:robinhood.option-date-chain/sellout-datetime
111+
"2021-07-16T19:00:00+00:00",
112+
:robinhood.option-contract/adjusted-mark-price 3.6,
113+
:robinhood.option-contract/bid-price 3.4,
114+
:robinhood.option-contract/implied-volatility 0.674616,
115+
:robinhood.option-date-chain/chain-id
116+
"b0707f5c-839a-44cd-ba9d-a92fb15ab932",
117+
:robinhood.option-date-chain/url
118+
"https://api.robinhood.com/options/instruments/f7e8bfbe-26a1-4300-952b-038d21f332ae/",
119+
:robinhood.option-date-chain/issue-date "2018-05-15",
120+
:robinhood.option-date-chain/expiration-date "2021-07-16",
121+
:robinhood.option-date-chain/created-at
122+
"2020-11-19T04:36:07.713986Z",
123+
:robinhood.option-contract/delta 0.828468,
124+
:robinhood.option-contract/low-fill-rate-sell-price 3.62,
125+
:robinhood.option-contract/high-fill-rate-sell-price 3.45,
126+
:robinhood.option-contract/chance-of-profit-short 0.637302,
127+
:robinhood.option-contract/volume 15,
128+
:robinhood.option-contract/chance-of-profit-long 0.362698,
129+
:robinhood.option-date-chain/updated-at
130+
"2020-11-19T04:36:07.713996Z",
131+
:robinhood.option-date-chain/chain-symbol "EAF",
132+
:robinhood.option-contract/theta -0.003522,
133+
:robinhood.option-date-chain/min-ticks
134+
#:robinhood.option-date-chain.min-ticks{:above-tick 0.1,
135+
:below-tick 0.05,
136+
:cutoff-price 3.0},
137+
:robinhood.option-contract/vega 0.018886,
138+
:robinhood.option-contract/open-interest 598,
139+
:robinhood.option-contract/ask-price 3.8,
140+
:robinhood.option-date-chain/strike-price 7.5,
141+
:robinhood.option-contract/mark-price 3.6,
142+
:robinhood.option-contract/gamma 0.05084,
143+
:robinhood.option-contract/last-trade-price 3.7,
144+
:robinhood.option-date-chain/rhs-tradability "untradable",
145+
:robinhood.option-contract/low-fill-rate-buy-price 3.58,
146+
:robinhood.option-contract/rho 0.02546,
147+
:robinhood.option-contract/previous-close-price 4.5,
148+
:robinhood.option-contract/ask-size 31,
149+
:robinhood.option-date-chain/type "call",
150+
:robinhood.option-contract/previous-close-date "2021-01-14",
151+
:robinhood.option-date-chain/state "active"}
152+
{:robinhood.option-contract/bid-size 34,
153+
:robinhood.option-contract/break-even-price 11.38,
154+
:robinhood.option-contract/high-price 1.4,
155+
:robinhood.option-contract/low-price 1.33,
156+
:robinhood.option-date-chain/id
157+
"e6dec319-3971-4fbb-8f3b-f74ad455b60f",
158+
:robinhood.option-contract/instrument
159+
"https://api.robinhood.com/options/instruments/e6dec319-3971-4fbb-8f3b-f74ad455b60f/",
160+
:robinhood.option-date-chain/tradability "tradable",
161+
:robinhood.option-contract/last-trade-size 3,
162+
:robinhood.option-contract/high-fill-rate-buy-price 1.43,
163+
:robinhood.option-date-chain/sellout-datetime
164+
"2021-03-19T19:00:00+00:00",
165+
:robinhood.option-contract/adjusted-mark-price 1.38,
166+
:robinhood.option-contract/bid-price 1.3,
167+
:robinhood.option-contract/implied-volatility 0.652445,
168+
:robinhood.option-date-chain/chain-id
169+
"b0707f5c-839a-44cd-ba9d-a92fb15ab932",
170+
:robinhood.option-date-chain/url
171+
"https://api.robinhood.com/options/instruments/e6dec319-3971-4fbb-8f3b-f74ad455b60f/",
172+
:robinhood.option-date-chain/issue-date "2018-05-15",
173+
:robinhood.option-date-chain/expiration-date "2021-03-19",
174+
:robinhood.option-date-chain/created-at
175+
"2021-01-14T05:30:06.546505Z",
176+
:robinhood.option-contract/delta 0.62552,
177+
:robinhood.option-contract/low-fill-rate-sell-price 1.38,
178+
:robinhood.option-contract/high-fill-rate-sell-price 1.31,
179+
:robinhood.option-contract/chance-of-profit-short 0.665686,
180+
:robinhood.option-contract/volume 6,
181+
:robinhood.option-contract/chance-of-profit-long 0.334314,
182+
:robinhood.option-date-chain/updated-at
183+
"2021-01-14T05:30:06.546519Z",
184+
:robinhood.option-date-chain/chain-symbol "EAF",
185+
:robinhood.option-contract/theta -0.008594,
186+
:robinhood.option-date-chain/min-ticks
187+
#:robinhood.option-date-chain.min-ticks{:above-tick 0.1,
188+
:below-tick 0.05,
189+
:cutoff-price 3.0},
190+
:robinhood.option-contract/vega 0.016545,
191+
:robinhood.option-contract/open-interest 1,
192+
:robinhood.option-contract/ask-price 1.45,
193+
:robinhood.option-date-chain/strike-price 10.0,
194+
:robinhood.option-contract/mark-price 1.375,
195+
:robinhood.option-contract/gamma 0.13309,
196+
:robinhood.option-contract/last-trade-price 1.35,
197+
:robinhood.option-date-chain/rhs-tradability "untradable",
198+
:robinhood.option-contract/low-fill-rate-buy-price 1.36,
199+
:robinhood.option-contract/rho 0.008959,
200+
:robinhood.option-contract/previous-close-price 2.13,
201+
:robinhood.option-contract/ask-size 49,
202+
:robinhood.option-date-chain/type "call",
203+
:robinhood.option-contract/previous-close-date "2021-01-14",
204+
:robinhood.option-date-chain/state "active"})
205+
```
206+
207+
### dev
208+
209+
My current development flow involves reverse engineering 1 robinhood screen at a time via Chrome's devtools and elbow grease. Whatever works in your browser will work dropped directly into a call to `client/get` or `client/post` (see utils.clj).
210+
211+
Steps to add any Robinhood API endpoint;
212+
213+
1. Find the data I am interested in within chrome dev tools (the network tools bar is great for this, especially via the filter bar > `Find all`).
214+
2. Click any name in the list of network requests. (PROTIP: robinhood makes loads of requests; cycle your selection here with up/down arrow keys.)
215+
3. Look at the `Headers` > Scroll to bottom > Open `Request Headers` if its closed.
216+
4. Go ahead and copy/paste this into robinhood.clj/utils.clj for some experimentation
217+
5. If you copied a `GET`, try to get a bare call to [`clj-http.client/get`](https://github.com/dakrone/clj-http#get) to work (use `clj-http.client/post` for a `POST`!)
218+
6. Transform the working `client/get` call block (with static data) into a function by allowing the passing of a parameter in place of each dynamic field.
219+
7. Trace information to its source calls by searching for unique strings/numbers back in the network-tab/filter-bar.
220+
8. If any of the source calls that pull prerequisite data are not yet implemented, then wash/rinse/repeat.
221+
222+
TODO; add to clojars, then add installation & usage instructs

config.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
todo:
2+
keyword: "TODO"
3+
bodyKeyword: "BODY"
4+
blobLines: 5 # number|boolean, 0 or false to disable
5+
autoAssign: true # string|string[]|boolean
6+
label: true # boolean|string|string[]
7+
reopenClosed: true # boolean

dev/user.clj

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
(ns user
2+
(:require [robinhood.clj.spec]
3+
[robinhood.clj.client]
4+
[expound.alpha :as expound]
5+
[clojure.spec.alpha :as s]
6+
[orchestra.spec.test :as stest]
7+
[clojure.tools.namespace.repl
8+
:refer [refresh set-refresh-dirs]]
9+
[reloaded.repl
10+
:refer [go init reset-all start stop system]]))
11+
12+
(set-refresh-dirs "dev/" "src/" "test/")
13+
14+
(alter-var-root #'s/*explain-out* (constantly expound/printer))
15+
16+
#_(stest/unstrument)
17+
18+
(stest/instrument)
19+
20+
(defn reset []
21+
(refresh)
22+
(stest/instrument))
23+
24+
#_(reset)

0 commit comments

Comments
 (0)