/** * @import { Options } from './options'; * @import { ColorName, Frequencies, Frequency } from './types/self'; */ /** * @param {Object} args * @param {Colors} args.colors * @param {LightweightCharts} args.lightweightCharts * @param {Signals} args.signals * @param {Utilities} args.utils * @param {Datasets} args.datasets * @param {Elements} args.elements * @param {Signal} args.lastValues */ export function init({ colors, datasets, elements, lightweightCharts, signals, utils, lastValues, }) { const simulationElement = elements.simulation; const parametersElement = window.document.createElement("div"); simulationElement.append(parametersElement); const resultsElement = window.document.createElement("div"); simulationElement.append(resultsElement); const frequencies = computeFrequencies(); const storagePrefix = "save-in-bitcoin"; const settings = { dollars: { initial: { amount: signals.createSignal(/** @type {number | null} */ (1000), { save: { ...utils.serde.number, id: `${storagePrefix}-initial-amount`, param: "initial-amount", }, }), }, topUp: { amount: signals.createSignal(/** @type {number | null} */ (150), { save: { ...utils.serde.number, id: `${storagePrefix}-top-up-amount`, param: "top-up-amount", }, }), frenquency: signals.createSignal( /** @type {Frequency} */ (frequencies.list[3].list[0]), { save: { ...frequencies.serde, id: `${storagePrefix}-top-up-freq`, param: "top-up-freq", }, }, ), }, }, swap: { amount: { initial: signals.createSignal(/** @type {number | null} */ (1000), { save: { ...utils.serde.number, id: `${storagePrefix}-initial-swap`, param: "initial-swap", }, }), recurrent: signals.createSignal(/** @type {number | null} */ (5), { save: { ...utils.serde.number, id: `${storagePrefix}-recurrent-swap`, param: "recurrent-swap", }, }), }, frequency: signals.createSignal( /** @type {Frequency} */ (frequencies.list[0]), { save: { ...frequencies.serde, id: `${storagePrefix}-swap-freq`, param: "swap-freq", }, }, ), }, interval: { start: signals.createSignal( /** @type {Date | null} */ (new Date("2021-04-15")), { save: { ...utils.serde.date, id: `${storagePrefix}-interval-start`, param: "interval-start", }, }, ), end: signals.createSignal(/** @type {Date | null} */ (new Date()), { save: { ...utils.serde.date, id: `${storagePrefix}-interval-end`, param: "interval-end", }, }), }, fees: { percentage: signals.createSignal(/** @type {number | null} */ (0.25), { save: { ...utils.serde.number, id: `${storagePrefix}-percentage`, param: "percentage", }, }), }, }; parametersElement.append( utils.dom.createHeader({ title: "Save in Bitcoin", description: "What if you bought Bitcoin in the past ?", }).headerElement, ); /** * @param {Object} param0 * @param {ColorName} param0.color * @param {string} param0.type * @param {string} param0.text */ function createColoredTypeHTML({ color, type, text }) { return `${createColoredSpan({ color, text: `${type}:` })} ${text}`; } /** * @param {Object} param0 * @param {ColorName} param0.color * @param {string} param0.text */ function createColoredSpan({ color, text }) { return `${text}`; } parametersElement.append( createFieldElement({ title: createColoredTypeHTML({ color: "green", type: "Dollars", text: "Initial Amount", }), description: "The amount of dollars you have ready on the exchange on day one.", input: createInputDollar({ id: "simulation-dollars-initial", title: "Initial Dollar Amount", signal: settings.dollars.initial.amount, }), }), ); parametersElement.append( createFieldElement({ title: createColoredTypeHTML({ color: "green", type: "Dollars", text: "Top Up Frequency", }), description: "The frequency at which you'll top up your account at the exchange.", input: utils.dom.createSelect({ id: "top-up-frequency", list: frequencies.list, signal: settings.dollars.topUp.frenquency, }), }), ); parametersElement.append( createFieldElement({ title: createColoredTypeHTML({ color: "green", type: "Dollars", text: "Top Up Amount", }), description: "The recurrent amount of dollars you'll be transfering to said exchange.", input: createInputDollar({ id: "simulation-dollars-later", title: "Top Up Dollar Amount", signal: settings.dollars.topUp.amount, }), }), ); parametersElement.append( createFieldElement({ title: createColoredTypeHTML({ color: "orange", type: "Swap", text: "Initial Amount", }), description: "The amount, if available, of dollars that will be used to buy Bitcoin on day one.", input: createInputDollar({ id: "simulation-dollars-later", title: "Initial Swap Amount", signal: settings.swap.amount.initial, }), }), ); parametersElement.append( createFieldElement({ title: createColoredTypeHTML({ color: "orange", type: "Swap", text: "Frequency", }), description: "The frequency at which you'll be buying Bitcoin.", input: utils.dom.createSelect({ id: "top-up-frequency", list: frequencies.list, signal: settings.swap.frequency, }), }), ); parametersElement.append( createFieldElement({ title: createColoredTypeHTML({ color: "orange", type: "Swap", text: "Recurrent Amount", }), description: "The recurrent amount, if available, of dollars that will be used to buy Bitcoin.", input: createInputDollar({ id: "simulation-dollars-later", title: "Recurrent Swap Amount", signal: settings.swap.amount.recurrent, }), }), ); parametersElement.append( createFieldElement({ title: createColoredTypeHTML({ color: "sky", type: "Interval", text: "Start", }), description: "The first day of the simulation.", input: createInputDateField({ signal: settings.interval.start, signals, utils, }), }), ); parametersElement.append( createFieldElement({ title: createColoredTypeHTML({ color: "sky", type: "Interval", text: "End", }), description: "The last day of the simulation.", input: createInputDateField({ signal: settings.interval.end, signals, utils, }), }), ); parametersElement.append( createFieldElement({ title: createColoredTypeHTML({ color: "red", type: "Fees", text: "Exchange", }), description: "The amount of trading fees (in %) at the exchange.", input: utils.dom.createInputNumberElement({ id: "", title: "", signal: settings.fees.percentage, min: 0, max: 50, step: 0.01, signals, }), }), ); const p1 = window.document.createElement("p"); const p2 = window.document.createElement("p"); const p3 = window.document.createElement("p"); const p4 = window.document.createElement("p"); const owner = signals.getOwner(); const closes = datasets.getOrCreate("date", "date-to-close"); closes.fetchRange(2009, new Date().getUTCFullYear()).then(() => { signals.runWithOwner(owner, () => { signals.createEffect( () => ({ initialDollarAmount: settings.dollars.initial.amount() || 0, topUpAmount: settings.dollars.topUp.amount() || 0, topUpFrequency: settings.dollars.topUp.frenquency(), initialSwap: settings.swap.amount.initial() || 0, recurrentSwap: settings.swap.amount.recurrent() || 0, swapFrequency: settings.swap.frequency(), start: settings.interval.start(), end: settings.interval.end(), fees: settings.fees.percentage(), }), ({ initialDollarAmount, topUpAmount, topUpFrequency, initialSwap, recurrentSwap, swapFrequency, start, end, fees, }) => { console.log({ start, end }); resultsElement.innerHTML = ""; resultsElement.append(p1); resultsElement.append(p2); resultsElement.append(p3); resultsElement.append(p4); if (!start || !end || start > end) return; const range = utils.date.getRange(start, end); /** @type {LineData