Published
Edited
Apr 12, 2020
Fork of Demo
1 fork
1 star
Insert cell
Insert cell
_ = await require("lodash@4")
Insert cell
_.VERSION
Insert cell
moment = await require("moment")
Insert cell
secondsAgg = 1800
Insert cell
startTS = (+(moment().endOf('day').subtract(1,'hour').subtract(1,'d'))).toFixed(0)+'000000'
Insert cell
sumArrayValues = values => values.reduce((p, c) => p + c, 0)
Insert cell
weightedMean = (factorsArray, weightsArray) => sumArrayValues(factorsArray.map((factor, index) => factor * weightsArray[index])) / sumArrayValues(weightsArray)
Insert cell
async function KAPI_Public(endpoint, parameters) {
var myInit = {
method: "GET",
headers: new Headers({ "Access-Control-Allow-Origin": "*" }),
mode: "cors",
type: "json",
cache: "default"
};
const proxyUrl = 'https://cors-anywhere.herokuapp.com/'
const urlWithParams = `${proxyUrl}https://api.kraken.com/0/public/${endpoint}?${parameters}`;
console.log(urlWithParams);

var myRequest = new Request(urlWithParams, myInit);

return fetch(myRequest)
.then((response) => response.json())
.then((data) => console.log('RAW',data) || data.result);
}
Insert cell
function toDateNum(string) {
//convert unix timestamp to milliseconds rather than seconds
var d = new Date(string * 1000);
return d;
}
Insert cell
async function KAPI_Trades(currency_pair, since) {
const nanoSince = since;
let api_results = await KAPI_Public(
"Trades",
"pair=" + currency_pair + "&since=" + nanoSince
);
let arrayForPair = api_results[currency_pair]
KAPI_Trades.last = api_results.last
// console.log('fullArray',arrayForPair)
let arrayOfTradeObjects = arrayForPair.map(tr => ({
'price':Number(tr[0]),
'volume':Number(tr[1]),
'timeStamp':tr[2],
'date': toDateNum(tr[2]),
'buySell':tr[3],
'limitMarket':tr[4],
'usuallyEmpty':tr[5],
}))
console.log(arrayOfTradeObjects)
return arrayOfTradeObjects
}
Insert cell
trades = (await KAPI_Trades("XETHZEUR", startTS)).concat(await KAPI_Trades("XETHZEUR", KAPI_Trades.last)).concat(await KAPI_Trades("XETHZEUR", KAPI_Trades.last)).concat(await KAPI_Trades("XETHZEUR", KAPI_Trades.last)).concat(await KAPI_Trades("XETHZEUR", KAPI_Trades.last)).concat(await KAPI_Trades("XETHZEUR", KAPI_Trades.last)).concat(await KAPI_Trades("XETHZEUR", KAPI_Trades.last))
Insert cell
async function getTradeMapGroupedByTime() {
let tradeMap = new Map(); // by time aggregated to 30sec

for (let eachTrade of trades) {
const timeSpan = Math.ceil(eachTrade.timeStamp / secondsAgg) * secondsAgg; // aggregated above
eachTrade.aggDate=toDateNum(timeSpan)
const arrayRefForTimeSpan = tradeMap.get(timeSpan) || [];
arrayRefForTimeSpan.push(eachTrade);
tradeMap.set(timeSpan, arrayRefForTimeSpan);
}
return tradeMap
}
Insert cell
tradeMap = getTradeMapGroupedByTime()
Insert cell
async function getTradeMapGroupedByTimeAndPrice(){
let mapByPrice = new Map();
let prevVwap=0
tradeMap.forEach((tradeArray, unixTimestamp) => {
console.log(toDateNum(unixTimestamp),'forEach tradeMap',tradeArray);
const groupedMap = new Map();
let innerPrevVwap=0
for(let tradeObj of tradeArray) {
let priceArr = groupedMap.get(tradeObj.price)? groupedMap.get(tradeObj.price).trades : []
priceArr.push(tradeObj)
const thisVwap=weightedMean(priceArr.map(prObj=>prObj.price),priceArr.map(prObj=>prObj.volume))
const tick= thisVwap-innerPrevVwap >= 0 ? 'u' : 'd'
groupedMap.set(tradeObj.price,{
trades: priceArr,
tradeCount: priceArr.length,
tradeVolume: _.sumBy(priceArr,'volume'),
vwap: thisVwap,
tick,
avgPrice: _.sumBy(priceArr,'price') / priceArr.length,
minPrice: _.minBy(priceArr,'price').price,
maxPrice: _.maxBy(priceArr,'price').price,
})
innerPrevVwap=thisVwap
}
// console.log('grouped',groupedMap)
// prevVwap=0
const thisVwap=weightedMean(tradeArray.map(prObj=>prObj.price),tradeArray.map(prObj=>prObj.volume))
const tick= thisVwap-prevVwap >= 0 ? 'u' : 'd'
mapByPrice.set(unixTimestamp, {
date: toDateNum(unixTimestamp),
trades: tradeArray,
tradeCount: tradeArray.length,
tradeVolume: _.sumBy(tradeArray,'volume'),
tick,
vwap: weightedMean(tradeArray.map(prObj=>prObj.price),tradeArray.map(prObj=>prObj.volume)),
avgPrice: _.sumBy(tradeArray,'price') / tradeArray.length,
minPrice: _.minBy(tradeArray,'price').price,
maxPrice: _.maxBy(tradeArray,'price').price,
tradesByPrice: {
trades:groupedMap,
},
})
prevVwap=thisVwap
})
return mapByPrice
}
Insert cell
data = getTradeMapGroupedByTimeAndPrice()
Insert cell
import { vl } from "@vega/vega-lite-api"
Insert cell
{
const chartWidth = 810
const brush = vl.selectInterval().encodings('x');
const opacity = vl.opacity().if(brush, vl.value(0.9)).value(0.1);
const volumeBars = vl.markBar().data([...data.values()])
.encode(
vl.x().fieldT('date'),
vl.y().field('tradeVolume').type('quantitative'),
opacity // modulate bar opacity based on the brush selection
)
.select(brush) // add interval brush selection to the chart
.width(chartWidth) // use the full default chart width
.height(50); // set chart height to 50 pixels
const vCandles= vl
.layer(
vl.markErrorbar({"ticks": true})
.data([...data.values()])
.encode(
vl.x().fieldT('date'),
vl.y().field('minPrice').type('quantitative').axis({title: 'price'}),
vl.y2().field('maxPrice').type('quantitative'),
vl.tooltip().field('vwap'),
vl.color({
"condition": {"test": "datum.tick === 'u'", "value": "green"},
"value": "red"
})
),
vl.markPoint({"filled": true, "color": "black"})
.data([...data.values()])
.encode(
vl.x().fieldT('date'),
vl.y().field('vwap').type('quantitative')
),
vl.markCircle({"filled": true, "color": "#CC888855"})
.data(trades)
.encode(
vl.x().fieldT('date'),
vl.y().field('price').type('quantitative'),
vl.size().field('volume').type('quantitative').scale({range: [0, 500]}),
),
// vl.markCircle({"filled": true, "color": "#CC888855"})
// .data(trades)
// .encode(
// vl.x().fieldT('aggDate'),
// vl.y().field('price').type('quantitative'),
// vl.size().field('volume').type('quantitative').scale({range: [0, 1000]}),
// ),
vl.markLine({ stroke: {
"condition": {"test": "datum.tick === 'u'", "value": "purple"},
"value": "red"
}})
.data([...data.values()])
.encode(
vl.x().fieldT('date'),
vl.y().field('vwap').type('quantitative').scale({zero:false}),
)
.select(vl.selectInterval().encodings('x')) // add interval brush selection to the chart
)
.width(chartWidth) // use the full default chart width
return vl.vconcat(volumeBars,vCandles).render()
}
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more