// Defined above
-// function updateChartInner(g, x, y, linesGroup, color, line, data) {
-// // Update axes with transitions
-// x.domain([0, d3.max(data, d => d.x)]);
-// g.select(".x-axis").transition().duration(1500).call(d3.axisBottom(x).ticks(10));
-// y.domain([0, d3.max(data, d => d.y)]);
-// g.select(".y-axis").transition().duration(1500).call(d3.axisLeft(y).ticks(5));
-
-// // Group data by basis function
-// const dataByFunction = Array.from(d3.group(data, d => d.b));
-// const keyFn = d => d[0];
+
// Defined above
+// function updateChartInner(g, x, y, linesGroup, color, line, data) {
+// // Update axes with transitions
+// x.domain([0, d3.max(data, d => d.x)]);
+// g.select(".x-axis").transition().duration(1500).call(d3.axisBottom(x).ticks(10));
+// y.domain([0, d3.max(data, d => d.y)]);
+// g.select(".y-axis").transition().duration(1500).call(d3.axisLeft(y).ticks(5));
+
+// // Group data by basis function
+// const dataByFunction = Array.from(d3.group(data, d => d.b));
+// const keyFn = d => d[0];
+
+// // Update basis function lines
+// const u = linesGroup.selectAll("path").data(dataByFunction, keyFn);
+// u.join(
+// enter => enter.append("path").attr("fill","none").attr("stroke-width",3)
+// .attr("stroke", (_, i) => color(i)).attr("d", d => line(d[1].map(pt => ({x: pt.x, y: 0}))))
+// .style("opacity",0),
+// update => update,
+// exit => exit.transition().duration(1000).style("opacity",0).remove()
+// )
+// .transition().duration(1000)
+// .attr("d", d => line(d[1]))
+// .attr("stroke", (_, i) => color(i))
+// .style("opacity",1);
+// }
-// // Update basis function lines
-// const u = linesGroup.selectAll("path").data(dataByFunction, keyFn);
-// u.join(
-// enter => enter.append("path").attr("fill","none").attr("stroke-width",3)
-// .attr("stroke", (_, i) => color(i)).attr("d", d => line(d[1].map(pt => ({x: pt.x, y: 0}))))
-// .style("opacity",0),
-// update => update,
-// exit => exit.transition().duration(1000).style("opacity",0).remove()
-// )
-// .transition().duration(1000)
-// .attr("d", d => line(d[1]))
-// .attr("stroke", (_, i) => color(i))
-// .style("opacity",1);
-// }
-
-chart0 = {
-// State variables for selected parameters
-let selectedMu =0.5;
-let selectedSig =1;
-let selectedNonc =0;
-let selectedTailw =1;
-const filteredData = () => bsplineData.filter(d =>
-Math.abs(selectedMu - d.mu) <0.001&&
- d.sig=== selectedSig &&
- d.nonc=== selectedNonc &&
- d.tailw=== selectedTailw
- );
-const container = d3.create("div")
-.style("max-width","none")
-.style("width","100%");;
-const controlsContainer = container.append("div")
-.style("display","flex")
-.style("gap","20px");
-// slider controls
-const sliders = [
- { label:'Mu',get: () => selectedMu,set: v => selectedMu = v,min:0.1,max:0.9,step:0.2 },
- { label:'Sigma',get: () =>Math.log2(selectedSig),set: v => selectedSig =2** v,min:-2,max:2,step:1 },
- { label:'Noncentrality',get: () => selectedNonc,set: v => selectedNonc = v,min:-4,max:4,step:2 },
- { label:'Tailweight',get: () =>Math.log2(selectedTailw),set: v => selectedTailw =2** v,min:-2,max:2,step:1 }
- ];
-// Build slider controls with D3 data join
-const sliderCont = controlsContainer.selectAll('div').data(sliders).join('div')
-.style('display','flex').style('align-items','center').style('gap','10px')
-.style('flex','1').style('min-width','0px');
- sliderCont.append('label').text(d => d.label+':').style('font-size','20px');
- sliderCont.append('input')
-.attr('type','range').attr('min', d => d.min).attr('max', d => d.max).attr('step', d => d.step)
-.property('value', d => d.get())
-.on('input',function(event, d) {
-const val =+this.value; d.set(val);
- d3.select(this.parentNode).select('span').text(d.label.match(/Sigma|Tailweight/) ?2**val : val);
-updateChart(filteredData());
- })
-.style('width','100%');
- sliderCont.append('span').text(d => (d.label.match(/Sigma|Tailweight/) ? d.get() : d.get()))
-.style('font-size','20px');
-
-// Add Reset button to clear all sliders to their defaults
- controlsContainer.append('button')
-.text('Reset')
-.style('font-size','20px')
-.style('align-self','center')
-.style('margin-left','auto')
-.on('click', () => {
-// reset state vars
- selectedMu =0.5;
- selectedSig =1;
- selectedNonc =0;
- selectedTailw =1;
-// update input positions
- sliderCont.selectAll('input').property('value', d => d.get());
-// update displayed labels
- sliderCont.selectAll('span')
-.text(d => d.label.match(/Sigma|Tailweight/) ? (2**d.get()) : d.get());
-// redraw chart
-updateChart(filteredData());
- });
-
-// Build SVG
-const width =1200;
-const height =450;
-const margin = {top:40,right:20,bottom:40,left:40};
-const innerWidth = width - margin.left- margin.right;
-const innerHeight = height - margin.top- margin.bottom;
-
-// Set controls container width to match SVG plot width
- controlsContainer.style("max-width","none").style("width","100%");
-// Distribute each control evenly and make sliders full-width
- controlsContainer.selectAll("div").style("flex","1").style("min-width","0px");
- controlsContainer.selectAll("input").style("width","100%").style("box-sizing","border-box");
-
-// Create scales
-const x = d3.scaleLinear()
-.domain([0,1])
-.range([0, innerWidth]);
-
-const y = d3.scaleLinear()
-.domain([0,1])
-.range([innerHeight,0]);
+chart0 = {
+// State variables for selected parameters
+let selectedMu =0.5;
+let selectedSig =1;
+let selectedNonc =0;
+let selectedTailw =1;
+const filteredData = () => bsplineData.filter(d =>
+Math.abs(selectedMu - d.mu) <0.001&&
+ d.sig=== selectedSig &&
+ d.nonc=== selectedNonc &&
+ d.tailw=== selectedTailw
+ );
+const container = d3.create("div")
+.style("max-width","none")
+.style("width","100%");;
+const controlsContainer = container.append("div")
+.style("display","flex")
+.style("gap","20px");
+// slider controls
+const sliders = [
+ { label:'Mu',get: () => selectedMu,set: v => selectedMu = v,min:0.1,max:0.9,step:0.2 },
+ { label:'Sigma',get: () =>Math.log2(selectedSig),set: v => selectedSig =2** v,min:-2,max:2,step:1 },
+ { label:'Noncentrality',get: () => selectedNonc,set: v => selectedNonc = v,min:-4,max:4,step:2 },
+ { label:'Tailweight',get: () =>Math.log2(selectedTailw),set: v => selectedTailw =2** v,min:-2,max:2,step:1 }
+ ];
+// Build slider controls with D3 data join
+const sliderCont = controlsContainer.selectAll('div').data(sliders).join('div')
+.style('display','flex').style('align-items','center').style('gap','10px')
+.style('flex','1').style('min-width','0px');
+ sliderCont.append('label').text(d => d.label+':').style('font-size','20px');
+ sliderCont.append('input')
+.attr('type','range').attr('min', d => d.min).attr('max', d => d.max).attr('step', d => d.step)
+.property('value', d => d.get())
+.on('input',function(event, d) {
+const val =+this.value; d.set(val);
+ d3.select(this.parentNode).select('span').text(d.label.match(/Sigma|Tailweight/) ?2**val : val);
+updateChart(filteredData());
+ })
+.style('width','100%');
+ sliderCont.append('span').text(d => (d.label.match(/Sigma|Tailweight/) ? d.get() : d.get()))
+.style('font-size','20px');
+
+// Add Reset button to clear all sliders to their defaults
+ controlsContainer.append('button')
+.text('Reset')
+.style('font-size','20px')
+.style('align-self','center')
+.style('margin-left','auto')
+.on('click', () => {
+// reset state vars
+ selectedMu =0.5;
+ selectedSig =1;
+ selectedNonc =0;
+ selectedTailw =1;
+// update input positions
+ sliderCont.selectAll('input').property('value', d => d.get());
+// update displayed labels
+ sliderCont.selectAll('span')
+.text(d => d.label.match(/Sigma|Tailweight/) ? (2**d.get()) : d.get());
+// redraw chart
+updateChart(filteredData());
+ });
+
+// Build SVG
+const width =1200;
+const height =450;
+const margin = {top:40,right:20,bottom:40,left:40};
+const innerWidth = width - margin.left- margin.right;
+const innerHeight = height - margin.top- margin.bottom;
+
+// Set controls container width to match SVG plot width
+ controlsContainer.style("max-width","none").style("width","100%");
+// Distribute each control evenly and make sliders full-width
+ controlsContainer.selectAll("div").style("flex","1").style("min-width","0px");
+ controlsContainer.selectAll("input").style("width","100%").style("box-sizing","border-box");
+
+// Create scales
+const x = d3.scaleLinear()
+.domain([0,1])
+.range([0, innerWidth]);
+
+const y = d3.scaleLinear()
+.domain([0,1])
+.range([innerHeight,0]);
+
+// Create a color scale for the basis functions
+const color = d3.scaleOrdinal(d3.schemeCategory10);
+
+// Create SVG
+const svg = d3.create("svg")
+.attr("width","100%")
+.attr("height","auto")
+.attr("viewBox", [0,0, width, height])
+.attr("preserveAspectRatio","xMidYMid meet")
+.attr("style","max-width: 100%; height: auto;");
+
+// Create the chart group
+const g = svg.append("g")
+.attr("transform",`translate(${margin.left},${margin.top})`);
-// Create a color scale for the basis functions
-const color = d3.scaleOrdinal(d3.schemeCategory10);
-
-// Create SVG
-const svg = d3.create("svg")
-.attr("width","100%")
-.attr("height","auto")
-.attr("viewBox", [0,0, width, height])
-.attr("preserveAspectRatio","xMidYMid meet")
-.attr("style","max-width: 100%; height: auto;");
-
-// Create the chart group
-const g = svg.append("g")
-.attr("transform",`translate(${margin.left},${margin.top})`);
-
-// Add axes
-const xAxis = g.append("g")
-.attr("transform",`translate(0,${innerHeight})`)
-.attr("class","x-axis")
-.call(d3.axisBottom(x).ticks(10))
-.style("font-size","20px");
-
-const yAxis = g.append("g")
-.attr("class","y-axis")
-.call(d3.axisLeft(y).ticks(5))
-.style("font-size","20px");
-
-// Add a horizontal line at y = 0
- g.append("line")
-.attr("x1",0)
-.attr("x2", innerWidth)
-.attr("y1",y(0))
-.attr("y2",y(0))
-.attr("stroke","#000")
-.attr("stroke-opacity",0.2);
-
-// Add gridlines
- g.append("g")
-.attr("class","grid-lines")
-.selectAll("line")
-.data(y.ticks(5))
-.join("line")
-.attr("x1",0)
-.attr("x2", innerWidth)
-.attr("y1", d =>y(d))
-.attr("y2", d =>y(d))
-.attr("stroke","#ccc")
-.attr("stroke-opacity",0.5);
-
-// Create a line generator
-const line = d3.line()
-.x(d =>x(d.x))
-.y(d =>y(d.y))
-.curve(d3.curveBasis);
+// Add axes
+const xAxis = g.append("g")
+.attr("transform",`translate(0,${innerHeight})`)
+.attr("class","x-axis")
+.call(d3.axisBottom(x).ticks(10))
+.style("font-size","20px");
+
+const yAxis = g.append("g")
+.attr("class","y-axis")
+.call(d3.axisLeft(y).ticks(5))
+.style("font-size","20px");
+
+// Add a horizontal line at y = 0
+ g.append("line")
+.attr("x1",0)
+.attr("x2", innerWidth)
+.attr("y1",y(0))
+.attr("y2",y(0))
+.attr("stroke","#000")
+.attr("stroke-opacity",0.2);
+
+// Add gridlines
+ g.append("g")
+.attr("class","grid-lines")
+.selectAll("line")
+.data(y.ticks(5))
+.join("line")
+.attr("x1",0)
+.attr("x2", innerWidth)
+.attr("y1", d =>y(d))
+.attr("y2", d =>y(d))
+.attr("stroke","#ccc")
+.attr("stroke-opacity",0.5);
+
+// Create a line generator
+const line = d3.line()
+.x(d =>x(d.x))
+.y(d =>y(d.y))
+.curve(d3.curveBasis);
+
+// Group to contain the basis function lines
+const linesGroup = g.append("g")
+.attr("class","basis-functions");
+
+// Store the current basis functions for transition
+let currentBasisFunctions =newMap();
+
+// Function to update the chart with new data
+functionupdateChart(data) {
+updateChartInner(g, x, y, linesGroup, color, line, data);
+ }
+
+// Store the update function
+ svg.node().update= updateChart;
-// Group to contain the basis function lines
-const linesGroup = g.append("g")
-.attr("class","basis-functions");
-
-// Store the current basis functions for transition
-let currentBasisFunctions =newMap();
-
-// Function to update the chart with new data
-functionupdateChart(data) {
-updateChartInner(g, x, y, linesGroup, color, line, data);
- }
-
-// Store the update function
- svg.node().update= updateChart;
-
-// Initial render
-updateChart(filteredData());
-
- container.node().appendChild(svg.node());
-return container.node();
-}
Time invariant
diff --git a/index.qmd b/index.qmd
index 61f1bcd..6d5c2de 100644
--- a/index.qmd
+++ b/index.qmd
@@ -1041,39 +1041,24 @@ chart = {
###
-:::: {.columns}
-
-::: {.column width="48%"}
-
Each day, $t = 1, 2, ... T$
- The **forecaster** receives predictions $\widehat{X}_{t,k}$ from $K$ **experts**
- The **forecaster** assigns weights $w_{t,k}$ to each **expert**
-- The **forecaster** calculates her prediction:
+- The **forecaster** calculates the prediction:
+
\begin{equation}
\widetilde{X}_{t} = \sum_{k=1}^K w_{t,k} \widehat{X}_{t,k}.
\label{eq_forecast_def}
\end{equation}
+
- The realization for $t$ is observed
-:::
+ The experts can be institutions, persons, or models
-::: {.column width="4%"}
+ The forecasts can be point-forecasts (i.e., mean or median) or full predictive distributions
-:::
-
-::: {.column width="48%"}
-
-- The experts can be institutions, persons, or models
-- The forecasts can be point-forecasts (i.e., mean or median) or full predictive distributions
-- We do not need a distributional assumption concerning the underlying data
-- @cesa2006prediction
-
-:::
-
-::::
-
----
+ @cesa2006prediction
## The Regret
@@ -3005,8 +2990,7 @@ Berrisch, J., Pappert, S., Ziel, F., & Arsova, A. (2023). *Finance Research Lett
### Motivation
-Understanding European Allowances (EUA) dynamics is important
-for several fields:
+Understanding European Emission Allowances (EUA)
Portfolio & Risk Management,
@@ -3179,7 +3163,8 @@ $$\mathbf{F} = (F_1, \ldots, F_K)^{\intercal}$$
Generalized non-central t-distributions
-- Time varying: expectation $\boldsymbol{\mu}_t = (\mu_{1,t}, \ldots, \mu_{K,t})^{\intercal}$
+- Time varying:
+ - expectation $\boldsymbol{\mu}_t = (\mu_{1,t}, \ldots, \mu_{K,t})^{\intercal}$
- variance: $\boldsymbol{\sigma}_{t}^2 = (\sigma_{1,t}^2, \ldots, \sigma_{K,t}^2)^{\intercal}$
- Time invariant
- degrees of freedom: $\boldsymbol{\nu} = (\nu_1, \ldots, \nu_K)^{\intercal}$