Created
May 7, 2021 19:57
-
-
Save kebman/5c4e4cc4da306a03645b910db397e1fe to your computer and use it in GitHub Desktop.
Coinbase Pro Order Formatting Tool in HTML5
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
<!DOCTYPE html> | |
<html class="no-js" lang="eng"> | |
<head> | |
<meta charset="utf-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> | |
<title></title> | |
<meta name="description" content="Order Formatting App"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<!-- <link rel="stylesheet" href="css/main.css"> --> | |
<style type="text/css"> | |
#outData { | |
/* background-color: red; */ | |
width: 60%; | |
/* float: right; */ | |
position: absolute; | |
padding: 1em; | |
padding-top: 0px; | |
margin-top: 0px; | |
margin-left: 55ex; | |
} | |
#outData p { | |
padding-top: 0px; | |
margin-top: 0.5ex; | |
} | |
article { | |
width: 50ex; | |
} | |
section { | |
position: relative; | |
} | |
</style> | |
</head> | |
<body> | |
<h1>Order Formatting App</h1> | |
<section> | |
<div id="outData" style="user-select: all"> | |
</div> | |
<article> | |
<form id="orderData" action="" method="post"> | |
<textarea rows="5" cols="50" name="input" onpaste="return true;" placeholder="Paste price data here."></textarea> | |
<!-- <input type="submit" value="submit" /> --> | |
</form> | |
</article> | |
<article> | |
<h1>Use</h1> | |
<p>Copy an order from Coinbase Pro > Orders > Filled, including fills. </p> | |
<p>Make sure you get everything form the Buy or Sell keyword and to the last fill. Then paste it into the above box.</p> | |
</article> | |
<article> | |
<h1>What</h1> | |
<p>This bare-bones app makes human-readable “JSON” out of raw orders copied from Coinbase Pro. It also calculates totals for later use with Profit Loss calculations, and it spits out a handy Break Even price based upon Coinbase Pro starter fees (0.5%).</p> | |
</article> | |
<article> | |
<h1>Background</h1> | |
<p>I often found myself copying orders from Coinbase Pro for two major reasons. First off Coinbase Pro doesn't show how much you spent on a trade. It's good to know how much you spent, with fees subtracted, in order to figure out your profit loss ratio. Additionally, I'd usually copy recent orders to find the break even point, so that I'd know where to trail my stop loss once a trade became profitable.</p> | |
<p>Complete re-build of an earlier version that spat out strings formatted for storage in spreadsheets such as Excel. New features include totals and break even, plus getting rid of the submit button entirely, and make the paste itself the submit trigger.</p> | |
</article> | |
<article> | |
<h1>Raw data example for testing</h1> | |
<pre style="user-select: all"> | |
Buy | |
ETH/BTC | |
0.01000000 ETH | |
0.01000000 | |
₿0.03874 | |
₿0.00000 | |
Apr 16, 2021 - 02:24:52 PM | |
Side | |
Market | |
Size | |
Trade ID | |
Price | |
Fee | |
Date | |
Buy | |
ETH/BTC | |
0.00066370 | |
14465622 | |
₿0.03874 | |
₿0.00000 | |
Apr 16, 2021 - 03:45:02 PM | |
Buy | |
ETH/BTC | |
0.00800000 | |
14465626 | |
₿0.03874 | |
₿0.00000 | |
Apr 16, 2021 - 03:45:02 PM | |
Buy | |
ETH/BTC | |
0.00133630 | |
14465627 | |
₿0.03874 | |
₿0.00000 | |
Apr 16, 2021 - 03:45:01 PM | |
</pre> | |
</article> | |
<article> | |
<p><a href="raw order data example.txt">More examples.</a></p> | |
</article> | |
</section> | |
</body> | |
</html> | |
<script type="text/javascript"> | |
const form = document.getElementById('orderData') | |
const outData = document.getElementById('outData') | |
const currencySymbols = [{"BTC":"₿"},{"ETH":"Ξ"},{"USD":"$"},{"EUR":"€"},{"GBP":"£"}] | |
let orderObject = { | |
order: {} | |
} | |
let orderStr = "" | |
// automagically fetch raw data pasted in form | |
form.addEventListener('paste', function(e) { | |
let input = this.input.value | |
let clipboardData = e.clipboardData || window.clipboardData | |
let raw = clipboardData.getData('Text') | |
prepData(raw) | |
e.preventDefault() | |
}, false) | |
// prepare data | |
function prepData(data) { | |
let trade = data.split('\n') | |
if (trade[0].trim() == 'Buy' || trade[0].trim() == 'Sell') { | |
// populate the orderObject with trade data | |
orderObject.order.side = trade[0].trim() | |
orderObject.order.market = trade[1].trim() | |
orderObject.order.size = trade[2].trim() | |
orderObject.order.filled = parseFloat(trade[3].trim()) | |
orderObject.order.price = trade[4].trim() | |
orderObject.order.fee = trade[5].trim() | |
orderObject.order.dateSet = trade[6].trim() | |
// prepare strings for calculations | |
let priceFloat = parseFloat(trade[4].slice(1).replace(/,/g, '')) | |
let priceCurrencySymbol = trade[4].slice(0,1) | |
let feeFloat = parseFloat(trade[5].slice(1).replace(/,/g, '')) | |
let feeCurrencySymbol = trade[5].slice(0,1) | |
let filledFloat = parseFloat(trade[3]) | |
// calculate totals while substracting fees | |
let total = filledFloat*priceFloat | |
if (trade[0].trim() == 'Buy') { | |
total = total + feeFloat | |
orderObject.order.breakEven = breakEven(priceFloat) | |
} | |
if (trade[0].trim() == 'Sell') { | |
total = total - feeFloat | |
} | |
orderObject.order.total = total | |
// check for fills | |
if (trade.length > 14) { | |
orderObject.fills = [] | |
if (trade[14].trim() == 'Buy' || trade[14].trim() == 'Sell') { | |
fills = trade.slice(14) | |
checkFills(fills) | |
} | |
} | |
formatOrder(orderObject) | |
} else { | |
console.error("Likely error in data") | |
} | |
} | |
// run through all fills as well | |
function checkFills(data) { | |
let fillObject = {} | |
fillObject.size = parseFloat(data[2].trim()) | |
fillObject.tradeId = parseInt(data[3].trim()) | |
fillObject.price = data[4].trim() | |
fillObject.fee = data[5].trim() | |
fillObject.dateFilled = data[6].trim() | |
// and save them as objects in an array | |
orderObject.fills.push(fillObject) | |
if (data.length > 7) { | |
if (data[7].trim() == 'Buy' || data[7].trim() == 'Sell') { | |
data = data.slice(7) | |
// callback | |
checkFills(data) | |
} | |
} | |
} | |
function breakEven(price) { | |
let feeRate = 0.005 // starter fee | |
let fee1 = 1*feeRate | |
let amount1 = 1-fee1 | |
let fee2 = (1+fee1)*feeRate | |
let amount2 = 1+fee2 | |
return amount2*price/amount1 | |
} | |
function formatOrder(obj) { | |
let order = "Order: {\nSide: "+ | |
obj.order.side | |
+"\nMarket: "+ | |
obj.order.market | |
+"\nSize: "+ | |
obj.order.size | |
+"\nFilled: "+ | |
obj.order.filled | |
+"\nPrice: "+ | |
obj.order.price.replace(/,/g, '') | |
+"\nFee: "+ | |
obj.order.fee | |
+"\nDate set: "+ | |
obj.order.dateSet | |
+"\nBreak even: "+ | |
obj.order.breakEven | |
+"\nTotal: "+ | |
obj.order.total | |
+"\n},\nFills: [{\n" | |
publish(order, obj) | |
} | |
function publish(data, obj) { | |
let pre = document.createElement("pre") | |
let node = document.createTextNode(data) | |
pre.append(node) | |
outData.appendChild(pre) | |
let i = 0 | |
obj.fills.forEach(function (element) { | |
i++ | |
let fill = "Date Filled: "+ | |
element.dateFilled | |
+"\nTrade ID: "+ | |
element.tradeId | |
+"\nSize: "+ | |
element.size+"\n" | |
if(i == obj.fills.length) { | |
fill+= "}]}\n" | |
} else { | |
fill+= "},{\n" | |
} | |
node = document.createTextNode(fill) | |
pre.append(node) | |
outData.appendChild(pre) | |
}) | |
} | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment