Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
halljson committed Jan 17, 2021
0 parents commit b1a1191
Show file tree
Hide file tree
Showing 15 changed files with 2,585 additions and 0 deletions.
1 change: 1 addition & 0 deletions .eastwood
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1555019149563
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
pom.xml*
*jar
/lib/
/classes/
/target/
.nrepl-port
.lein-repl-history
.lein-deps-sum
.lein-failures
*.swp
autodoc/**
*.DS_Store
dev-fixtures
30 changes: 30 additions & 0 deletions ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG] - ..."
labels: bug
assignees: ''

---

### Description
- Provide a good description of the issue

### Steps to Reproduce
- Provide a description of the bug
- Any relevant information on how you go to this state
- Bonus points for a video recording (either from you or from FullStory)

### Logs
- Provide relevant & unbiased information (logs, market movements, Robinhood screenshots, etc) that might help diagnose the issue

### Business Impact / Severity Level
- Provide a severity level of this bug

- 1 - Critical Impact / System Down
- 2 - Significant Impact
- 3 - Normal/Minor Impact
- 4 - Low/Informational

### Acceptance Criteria
- [ ] These are subtasks for this bug
18 changes: 18 additions & 0 deletions ISSUE_TEMPLATE/feature-request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[FEATURE] - ..."
labels: enhancement
assignees: ''

---

#### Description
- This section is a brief description of the feature ("As a X, I should be able to Y, so that I can Z")
- Make sure to link this to the appropriate Epic

#### Acceptance Criteria
- [ ] These are the subtasks for this feature

#### Design
- Please attach any Figma links or design assets
222 changes: 222 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
# robinhood.clj

A lightweight clojure wrapper for the [Robinhood Web API](https://github.com/sanko/Robinhood/).

All use cases must follow the [Robinhood TOS](
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.

### Authenticating with environment variables

You'll have to set up your machine's environment variables before hitting any endpoints that require authentication.

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.

```
export ROBINHOOD_USER="..."
export ROBINHOOD_PASS="..."
export ROBINHOOD_DEVICE_TOKEN="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
;Don't forget to restart any running repls
```

After adding the above environment variables, `lein test` should run without any failures.

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.

### Caution

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.

I've added some notes on how I'm scraping by in the `Dev` section at the bottom.

### REPL Usage

Cd into robinhood.clj and run `lein repl` in order to follow along:

Login:
``` clojure
(use 'robinhood.clj.auth)

# Get a robinhood client
(def rc' (authed-client))

;; output:
:robinhood{:access-token "xxxxxxxxx"}
```

Fetch Quotes:
``` clojure
(use 'robinhood.clj.auth)
(use 'robinhood.clj.client)

(quotes (authed-client) {:symbols "AAPL,MSFT"})

;; output:
(#:robinhood.quote{:updated-at "2021-01-16T01:00:00Z",
:instrument
"https://api.robinhood.com/instruments/450dfc6d-5510-4d40-abfb-f633b7d9be3e/",
:bid-price 126.41,
:last-trade-price-source "consolidated",
:symbol "AAPL",
:last-trade-price 127.14,
:ask-price 500.0,
:bid-size 21,
:ask-size 596,
:last-extended-hours-trade-price 126.82,
:previous-close 128.91,
:has-traded true,
:trading-halted false,
:adjusted-previous-close 128.91,
:previous-close-date "2021-01-14"}
#:robinhood.quote{:updated-at "2021-01-16T01:00:00Z",
:instrument
"https://api.robinhood.com/instruments/50810c35-d215-4866-9758-0ada4ac79ffa/",
:bid-price 210.91,
:last-trade-price-source "consolidated",
:symbol "MSFT",
:last-trade-price 212.65,
:ask-price 215.86,
:bid-size 30,
:ask-size 200,
:last-extended-hours-trade-price 212.55,
:previous-close 213.02,
:has-traded true,
:trading-halted false,
:adjusted-previous-close 213.02,
:previous-close-date "2021-01-14"})
```



See call options on a ticker:
``` clojure
(use 'robinhood.clj.auth)
(use 'robinhood.clj.client)

(take 2 ;for brevity
(get-option-chain-prices (authed-client) {:symbols "EAF"} "call"))

;; output (you'll see some logs of all the requests made):
({:robinhood.option-contract/bid-size 101,
:robinhood.option-contract/break-even-price 11.1,
:robinhood.option-contract/high-price 3.7,
:robinhood.option-contract/low-price 3.4,
:robinhood.option-date-chain/id
"f7e8bfbe-26a1-4300-952b-038d21f332ae",
:robinhood.option-contract/instrument
"https://api.robinhood.com/options/instruments/f7e8bfbe-26a1-4300-952b-038d21f332ae/",
:robinhood.option-date-chain/tradability "tradable",
:robinhood.option-contract/last-trade-size 10,
:robinhood.option-contract/high-fill-rate-buy-price 3.74,
:robinhood.option-date-chain/sellout-datetime
"2021-07-16T19:00:00+00:00",
:robinhood.option-contract/adjusted-mark-price 3.6,
:robinhood.option-contract/bid-price 3.4,
:robinhood.option-contract/implied-volatility 0.674616,
:robinhood.option-date-chain/chain-id
"b0707f5c-839a-44cd-ba9d-a92fb15ab932",
:robinhood.option-date-chain/url
"https://api.robinhood.com/options/instruments/f7e8bfbe-26a1-4300-952b-038d21f332ae/",
:robinhood.option-date-chain/issue-date "2018-05-15",
:robinhood.option-date-chain/expiration-date "2021-07-16",
:robinhood.option-date-chain/created-at
"2020-11-19T04:36:07.713986Z",
:robinhood.option-contract/delta 0.828468,
:robinhood.option-contract/low-fill-rate-sell-price 3.62,
:robinhood.option-contract/high-fill-rate-sell-price 3.45,
:robinhood.option-contract/chance-of-profit-short 0.637302,
:robinhood.option-contract/volume 15,
:robinhood.option-contract/chance-of-profit-long 0.362698,
:robinhood.option-date-chain/updated-at
"2020-11-19T04:36:07.713996Z",
:robinhood.option-date-chain/chain-symbol "EAF",
:robinhood.option-contract/theta -0.003522,
:robinhood.option-date-chain/min-ticks
#:robinhood.option-date-chain.min-ticks{:above-tick 0.1,
:below-tick 0.05,
:cutoff-price 3.0},
:robinhood.option-contract/vega 0.018886,
:robinhood.option-contract/open-interest 598,
:robinhood.option-contract/ask-price 3.8,
:robinhood.option-date-chain/strike-price 7.5,
:robinhood.option-contract/mark-price 3.6,
:robinhood.option-contract/gamma 0.05084,
:robinhood.option-contract/last-trade-price 3.7,
:robinhood.option-date-chain/rhs-tradability "untradable",
:robinhood.option-contract/low-fill-rate-buy-price 3.58,
:robinhood.option-contract/rho 0.02546,
:robinhood.option-contract/previous-close-price 4.5,
:robinhood.option-contract/ask-size 31,
:robinhood.option-date-chain/type "call",
:robinhood.option-contract/previous-close-date "2021-01-14",
:robinhood.option-date-chain/state "active"}
{:robinhood.option-contract/bid-size 34,
:robinhood.option-contract/break-even-price 11.38,
:robinhood.option-contract/high-price 1.4,
:robinhood.option-contract/low-price 1.33,
:robinhood.option-date-chain/id
"e6dec319-3971-4fbb-8f3b-f74ad455b60f",
:robinhood.option-contract/instrument
"https://api.robinhood.com/options/instruments/e6dec319-3971-4fbb-8f3b-f74ad455b60f/",
:robinhood.option-date-chain/tradability "tradable",
:robinhood.option-contract/last-trade-size 3,
:robinhood.option-contract/high-fill-rate-buy-price 1.43,
:robinhood.option-date-chain/sellout-datetime
"2021-03-19T19:00:00+00:00",
:robinhood.option-contract/adjusted-mark-price 1.38,
:robinhood.option-contract/bid-price 1.3,
:robinhood.option-contract/implied-volatility 0.652445,
:robinhood.option-date-chain/chain-id
"b0707f5c-839a-44cd-ba9d-a92fb15ab932",
:robinhood.option-date-chain/url
"https://api.robinhood.com/options/instruments/e6dec319-3971-4fbb-8f3b-f74ad455b60f/",
:robinhood.option-date-chain/issue-date "2018-05-15",
:robinhood.option-date-chain/expiration-date "2021-03-19",
:robinhood.option-date-chain/created-at
"2021-01-14T05:30:06.546505Z",
:robinhood.option-contract/delta 0.62552,
:robinhood.option-contract/low-fill-rate-sell-price 1.38,
:robinhood.option-contract/high-fill-rate-sell-price 1.31,
:robinhood.option-contract/chance-of-profit-short 0.665686,
:robinhood.option-contract/volume 6,
:robinhood.option-contract/chance-of-profit-long 0.334314,
:robinhood.option-date-chain/updated-at
"2021-01-14T05:30:06.546519Z",
:robinhood.option-date-chain/chain-symbol "EAF",
:robinhood.option-contract/theta -0.008594,
:robinhood.option-date-chain/min-ticks
#:robinhood.option-date-chain.min-ticks{:above-tick 0.1,
:below-tick 0.05,
:cutoff-price 3.0},
:robinhood.option-contract/vega 0.016545,
:robinhood.option-contract/open-interest 1,
:robinhood.option-contract/ask-price 1.45,
:robinhood.option-date-chain/strike-price 10.0,
:robinhood.option-contract/mark-price 1.375,
:robinhood.option-contract/gamma 0.13309,
:robinhood.option-contract/last-trade-price 1.35,
:robinhood.option-date-chain/rhs-tradability "untradable",
:robinhood.option-contract/low-fill-rate-buy-price 1.36,
:robinhood.option-contract/rho 0.008959,
:robinhood.option-contract/previous-close-price 2.13,
:robinhood.option-contract/ask-size 49,
:robinhood.option-date-chain/type "call",
:robinhood.option-contract/previous-close-date "2021-01-14",
:robinhood.option-date-chain/state "active"})
```

### dev

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).

Steps to add any Robinhood API endpoint;

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`).
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.)
3. Look at the `Headers` > Scroll to bottom > Open `Request Headers` if its closed.
4. Go ahead and copy/paste this into robinhood.clj/utils.clj for some experimentation
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`!)
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.
7. Trace information to its source calls by searching for unique strings/numbers back in the network-tab/filter-bar.
8. If any of the source calls that pull prerequisite data are not yet implemented, then wash/rinse/repeat.

TODO; add to clojars, then add installation & usage instructs
7 changes: 7 additions & 0 deletions config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
todo:
keyword: "TODO"
bodyKeyword: "BODY"
blobLines: 5 # number|boolean, 0 or false to disable
autoAssign: true # string|string[]|boolean
label: true # boolean|string|string[]
reopenClosed: true # boolean
24 changes: 24 additions & 0 deletions dev/user.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
(ns user
(:require [robinhood.clj.spec]
[robinhood.clj.client]
[expound.alpha :as expound]
[clojure.spec.alpha :as s]
[orchestra.spec.test :as stest]
[clojure.tools.namespace.repl
:refer [refresh set-refresh-dirs]]
[reloaded.repl
:refer [go init reset-all start stop system]]))

(set-refresh-dirs "dev/" "src/" "test/")

(alter-var-root #'s/*explain-out* (constantly expound/printer))

#_(stest/unstrument)

(stest/instrument)

(defn reset []
(refresh)
(stest/instrument))

#_(reset)
Loading

0 comments on commit b1a1191

Please sign in to comment.