Created
July 5, 2021 23:02
-
-
Save kevinkassimo/6d8559c00c4bdb6d38faf7297a2bdf66 to your computer and use it in GitHub Desktop.
Export Robinhood records to CSV format that can be imported to simplywall.st
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Deps: pandas, grequests | |
# READ ME BEFORE START! | |
# Please install: pandas, grequests | |
# pip3 install pandas grequests | |
# | |
# Usage: | |
# python3 robinhood_to_simplywallst.py [source_json] [optional_custom_ticker_file] | |
# | |
# <source_json>: JSON file of your historical transactions downloaded from https://api.robinhood.com/orders/ | |
# <optional_custom_ticker_file>: a JSON file following a simple JSON dictionary format that replaces a ticker symbol with a custom one. | |
# This might be necessary when there is confusion about the ticker symbol. | |
# For example, for a ticker symbol "YOU", you might want to replace it with "NYSE:YOU" | |
# To do such, simply have your <optional_custom_ticker_file> contain {"YOU": "NYSE:YOU"} | |
# If argument not provided, the default filename to try is "./custom_tickers.json" | |
# | |
# The output file will be a CSV file with the same name as <source_json> but with .json replaced with .csv | |
import json | |
from sys import argv | |
import grequests | |
import pandas as pd | |
in_filename = argv[1] | |
out_filename = in_filename.replace(".json", ".csv") | |
def exception_handler(request, exception): | |
print(request, exception) | |
# Use custom | |
custom_ticker = {} | |
try: | |
with open(argv[2] if len(argv) > 2 else "./custom_tickers.json", 'r') as f: | |
custom_ticker = json.load(f) | |
except Exception: | |
print(">>> No custom ticker replacer found") | |
def patch_custom_ticker(ticker): | |
return custom_ticker[ticker] if ticker in custom_ticker else ticker | |
def main(): | |
# Get this JSON from: https://api.robinhood.com/orders/ | |
with open(argv[1], 'r') as f: | |
j = json.load(f) | |
j = j["results"] | |
urls = set() | |
instrument_to_ticker = {} | |
# Extract JSON | |
df = pd.DataFrame(j) | |
# Translate side into something that simplywall.st can recognize | |
for i, r in df.iterrows(): | |
# Drop canceled rows | |
if r["state"] == "cancelled": | |
df.drop(i, inplace=True) | |
continue | |
# buy -> Buy | |
df.loc[i, "side"] = r["side"].capitalize() | |
# Date format to YYYY-MM-DD | |
df.loc[i, "created_at"] = r["created_at"][:r["created_at"].index("T")] | |
# Prep with instrument_id -> ticker mapping first. Robinhood does not immediately include ticker symbol in the JSON | |
urls.add(f"https://api.robinhood.com/instruments/{r['instrument_id']}/") | |
# Get the actual tickers | |
requests = (grequests.get(u) for u in urls) | |
for res in grequests.map(requests, exception_handler=exception_handler): | |
rjson = res.json() | |
instrument_to_ticker[rjson["id"]] = rjson["symbol"] | |
for i, r in df.iterrows(): | |
df.loc[i, "instrument_id"] = patch_custom_ticker(instrument_to_ticker[r["instrument_id"]]) | |
df = df.rename(columns={ | |
"instrument_id": "Ticker", | |
"side": "Type", | |
"price": "Price", | |
"quantity": "Shares", | |
"created_at": "Date" | |
}) | |
# Output | |
df[["Ticker", "Type", "Price", "Shares", "Date"]].to_csv(out_filename) | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment