Published
Edited
Jun 30, 2022
10 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
additional_indicators.includes("Volume")
? Plot.plot({
y: { grid: true, axis: "right", label: "Volume ↑" },
marks: [
Plot.ruleX(data_withFcIndicators, {
x: "date",
y: "volume",
stroke: "color",
strokeWidth: 850 / data_final.filter((d) => d.date).length,
opacity: 0.7
})
],
width: 1200,
height: 100
})
: html`<p></p>`
Insert cell
Insert cell
additional_indicators.includes("MACD")
? Plot.plot({
marks: [
Plot.lineY(data_withFcIndicators, {
x: "date",
y: "macd",
stroke: "#FFAE42"
}),
Plot.lineY(data_withFcIndicators, {
x: "date",
y: "macdSignal",
stroke: "#800080"
}),
Plot.rectY(data_withFcIndicators, {
x: "date",
y: "macdDivergence",
interval: d3.utcDay,
fill: (d) => (d.macdDivergence >= 0 ? "#228B22" : "#ff0000"),
opacity: 0.7
})
],
width: 1000,
height: 100,
x: { grid: true },
y: { grid: true, axis: "right", label: "MACD" }
})
: html`<p></p>`
Insert cell
Insert cell
additional_indicators.includes("RSI")
? Plot.plot({
marks: [
Plot.lineY(data_withFcIndicators, {
x: "date",
y: "rsi",
z: null,
stroke: (d) => (d.rsi > 70 || d.rsi < 30 ? "#ff0000" : "#228B22")
}),
Plot.ruleY([70], {
strokeDasharray: [10, 5],
opacity: 1,
stroke: "#ADD8E6"
}),

Plot.ruleY([30], {
strokeDasharray: [10, 5],
opacity: 1,
stroke: "#ADD8E6"
}),
Plot.areaY(rsi_upper_lower, {
x: "date",
y1: "30",
y2: "70",
fill: "#a8daeb",
opacity: 0.3
})
],
width: 1110,
height: 100,
x: { grid: true },
y: { grid: true, axis: "right", label: "RSI ↑" }
})
: html`<p></p>`
Insert cell
Insert cell
additional_indicators.includes("Stochastic Oscillator")
? Plot.plot({
marks: [
Plot.lineY(data_withFcIndicators, {
x: "date",
y: "stochasticOscillatorK",
z: null,
stroke: "#FFAE42"
}),
Plot.lineY(data_withFcIndicators, {
x: "date",
y: "stochasticOscillatorD",
z: null,
stroke: "#800080",
strokeOpacity: 0.5
}),
Plot.ruleX(data_withFearGreedIndex, {
x: "date",
stroke: (d) =>
d.stochasticOscillatorK >= d.stochasticOscillatorD
? "green"
: "red",
strokeWidth: 7,
opacity: 0.08
})
],
width: 1110,
height: 100,
x: { grid: true },
y: { grid: true, axis: "right", label: "Stochastic Oscillator" }
})
: html`<p></p>`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
data_final = data_withFearGreedIndex
Insert cell
Inputs.table(data_final)
Insert cell
Insert cell
data_yahooRaw = FileAttachment("ETH-USD@3.csv").csv({typed: true})
Insert cell
Insert cell
SummaryTable(data_yahooRaw)
Insert cell
Inputs.table(data_yahooRaw)
Insert cell
Insert cell
data_yahooWithRenamedColumns = aq.from(data_yahooRaw)
.rename({Date: "date"})
.rename({Open: "open"})
.rename({High: "high"})
.rename({Low: "low"})
.rename({Close: "close"})
.rename({"Adj Close": "adjClose"})
.rename({Volume: "volume"})
.objects()
Insert cell
Insert cell
data_yahooFiltered = aq.from(data_yahooWithRenamedColumns)
.params({
yearStart: new Date(+control_timeRange[0], 0, 1).getTime(),
yearEnd: new Date(+control_timeRange[1], 0, 0).getTime()
})
.filter ( (d, params) => d["date"] > params.yearStart)
.filter ( (d, params) => d["date"] < params.yearEnd)
.derive ({color: d => d.close < d.open ? "crimson" : "oliveDrab"})
.objects()
Insert cell
Inputs.table(data_yahooFiltered)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof control_bollingerPeriod = Inputs.range([2, 200], {
value: 7,
step: 1,
label: "Bollinger Period"
})
Insert cell
viewof control_bollingerSD = Inputs.range([0.5, 4], {
value: 2,
label: "Bollinger SD",
step: 0.1
})
Insert cell
viewof control_maLookbackPeriod = Inputs.range([1, 200], {label: "MA Period", value: 9, step: 1})
Insert cell
viewof control_macdSignalPeriod = Inputs.range([1, 200], {label: "MACD Signal Period", value: 9, step: 1, width: 300})
Insert cell
viewof control_macdFastPeriod = Inputs.range([1, 200], {label: "MACD Fast Period", value: 12, step: 1})
Insert cell
viewof control_macdSlowPeriod = Inputs.range([1, 200], {label: "MACD Slow Period", value: 26, step: 1})
Insert cell
viewof control_rsiPeriod = Inputs.range([1, 200], {label: "RSI Period", value: 14, step: 1})
Insert cell
viewof control_stochasticOscillatorKPeriod = Inputs.range([1, 200], {label: "Stochastic Oscillator K Period", value: 5, step: 1})
Insert cell
viewof control_stochasticOscillatorDPeriod = Inputs.range([1, 200], {label: "Stochastic Oscillator D Period", value: 3, step: 1})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
showMe(`maColumn = fc.indicatorMovingAverage()
.period(control_maLookbackPeriod)
.value(d => d.close)
(data_yahooFiltered)`,{

label: 'How do I calculate an indicator?',
dependencies: {fc, data_yahooFiltered, control_maLookbackPeriod}
}
)
Insert cell
maColumn = fc.indicatorMovingAverage()
.period(control_maLookbackPeriod)
.value(d => d.close)
(data_yahooFiltered)
Insert cell
Insert cell
emaColumn = fc.indicatorExponentialMovingAverage()
.period(9)
.value(d => d.close)
(data_yahooFiltered)
Insert cell
Insert cell
rsiColumn = fc.indicatorRelativeStrengthIndex()
.value(d => d.close)
.period(control_rsiPeriod)
(data_yahooFiltered)
Insert cell
Insert cell
bollingerColumn = fc.indicatorBollingerBands()
.value(d => d.close)
.period(control_bollingerPeriod)
.multiplier(control_bollingerSD)
(data_yahooFiltered)
Insert cell
Insert cell
macdColumn = fc.indicatorMacd()
.value(d => d.close)
.fastPeriod(d => control_macdFastPeriod)
.slowPeriod(d => control_macdSlowPeriod)
.signalPeriod(d => control_macdSignalPeriod)
(data_yahooFiltered)
Insert cell
Insert cell
stochasticOscillatorColumn = fc.indicatorStochasticOscillator()
.lowValue(d => d.low)
.highValue(d => d.high)
.closeValue(d => d.close)
.kPeriod( control_stochasticOscillatorKPeriod )
.dPeriod( control_stochasticOscillatorDPeriod )
(data_yahooFiltered)
Insert cell
Insert cell
data_withFcIndicators = data_yahooFiltered.map( (d, i) => ({
ma: maColumn[i],
ema: emaColumn[i],
macd: macdColumn[i].macd,
macdSignal: macdColumn[i].signal,
macdDivergence: macdColumn[i].divergence,
rsi: rsiColumn[i],
stochasticOscillatorK: stochasticOscillatorColumn[i].k,
stochasticOscillatorD: stochasticOscillatorColumn[i].d,
bollingerUpper: bollingerColumn[i].upper,
bollingerAverage: bollingerColumn[i].average,
bollingerLower: bollingerColumn[i].lower,
...d
}))
Insert cell
Insert cell
Insert cell
Insert cell
currentEthereumPrice = d3.json( "https://www.binance.com/api/v3/ticker/price?symbol=ETHUSDT").then( response => {
return +response.price
} )
Insert cell
Insert cell
Insert cell
Insert cell
data_fearGreedIndex_raw = d3.json("https://api.alternative.me/fng/?limit=0&format=json")
Insert cell
data_fearGreedIndex = aq.from(data_fearGreedIndex_raw.data)
.derive({date: aq.escape(d => new Date(+d.timestamp * 1000))})
.filter ( aq.escape( d =>
d["date"].getFullYear() >= control_timeRange[0] &&
d["date"].getFullYear() <= control_timeRange[1]
))
.derive({value: d => +d.value}) // make numeric
.select('value_classification','date','value')
.rename({value: "fearGreedIndex"})
.rename({value_classification: "fearGreedIndexClassification"})
.objects()
Insert cell
Insert cell
data_withFearGreedIndex = aq.from(data_withFcIndicators)
.join_left(aq.from(data_fearGreedIndex), ["date", "date"])
.objects()
Insert cell
Insert cell
Insert cell
Insert cell
viewof table = Inputs.table(data_withFearGreedIndex)
Insert cell
rsi_upper_lower = aq
.from(data_withFcIndicators)
.derive({ 30: (d) => 30 })
.derive({ 70: (d) => 70 })
.objects() // Uncomment to return an array of objects
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
import {Wrangler, op} from "@observablehq/data-wrangler"
Insert cell
import {rangeSlider} from '@mootari/range-slider'
Insert cell
import { SummaryTable } from "@observablehq/summary-table"
Insert cell
fc = require('d3fc')
Insert cell
import {Plot} from "@mkfreeman/plot-tooltip"
Insert cell
Insert cell
Insert cell
<!-- Style tells the cell to put any elements side by side. -->
<!-- You don't need to modify the style. -->
<style>
.controlPanel form{
display: inline-block;
vertical-align: top;
padding: 10px;
max-width: 140px;
}

</style>
Insert cell
import {toc} from "@nebrius/indented-toc"
Insert cell
import {showMe} from "@observablehq/show-me"
Insert cell
import {howTo} from "@clokman/howto"
Insert cell
import { displayCaution } from "@mkfreeman/utilities"
Insert cell
import {imageToDo} from "@clokman/student-blocks"
Insert cell
imageToDo
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