diff --git a/Tests/test_iTBar.cs b/Tests/test_iTBar.cs index 1cf5f78..5979617 100644 --- a/Tests/test_iTBar.cs +++ b/Tests/test_iTBar.cs @@ -25,7 +25,7 @@ public BarIndicatorTests() private static readonly ITValue[] indicators = new ITValue[] { new Atr(period: 14), - new Jvolty(period: 14) + // Add other TBar-based indicators here }; @@ -80,14 +80,14 @@ private static MethodInfo FindCalcMethod(Type type) if (methods.Count > 0) { // Prefer the method with TBar parameter - var method = methods.FirstOrDefault(m => + var method = methods.Find(m => { var parameters = m.GetParameters(); return parameters.Length == 1 && parameters[0].ParameterType == typeof(TBar); }); // If not found, return the first method - return method ?? methods.First(); + return method ?? methods[0]; } type = type.BaseType!; diff --git a/Tests/test_quantower.cs b/Tests/test_quantower.cs index 844f173..2343083 100644 --- a/Tests/test_quantower.cs +++ b/Tests/test_quantower.cs @@ -13,7 +13,7 @@ namespace QuanTAlib { public class QuantowerTests { - private void TestIndicator(string fieldName = "ma") where T : Indicator, new() + private static void TestIndicator(string fieldName = "ma") where T : Indicator, new() { var indicator = new T(); try @@ -95,7 +95,6 @@ public class QuantowerTests // Volatility Indicators [Fact] public void Atr() => TestIndicator("atr"); - [Fact] public void Jvolty() => TestIndicator("jvolty"); [Fact] public void Historical() => TestIndicator("historical"); [Fact] public void Realized() => TestIndicator("realized"); diff --git a/Tests/test_updates_volatility.cs b/Tests/test_updates_volatility.cs index 901006c..ba7976e 100644 --- a/Tests/test_updates_volatility.cs +++ b/Tests/test_updates_volatility.cs @@ -57,21 +57,6 @@ public void Historical_Update() Assert.Equal(initialValue, finalValue, precision); } - [Fact] - public void Jvolty_Update() - { - var indicator = new Jvolty(period: 14); - double initialValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: true)); - - for (int i = 0; i < RandomUpdates; i++) - { - indicator.Calc(GetRandomBar(false)); - } - double finalValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: false)); - - Assert.Equal(initialValue, finalValue, precision); - } - [Fact] public void Realized_Update() { diff --git a/docs/Progress.csv b/docs/Progress.csv new file mode 100644 index 0000000..7ea5a50 --- /dev/null +++ b/docs/Progress.csv @@ -0,0 +1,134 @@ +AC,Acceleration Oscillator +AD,Chaikin A/D Line +ADOSC,Chaikin A/D Oscillator +ADL,Accumulation / Distribution Line +ADX,Average Directional Movement Index +ADXR,Average Directional Movement Index Rating +Alligator,Alligator Indicator +ALMA,Arnaud Legoux Moving Average +AO,Awesome Oscillator +APO,Absolute Price Oscillator +AROON,Aroon Indicator +AROONOSC,Aroon Oscillator +ATS,ATR Trailing Stop +ATR,Average True Range +AVGPRICE,Average Price +BB,Bollinger Bands +BBF,Bollinger Bands Flat +BBP,Bull and Bear Power +BC,Beta Coefficient +BETA,Beta +BOP,Balance of Power +CCI,Commodity Channel Index +CE,Chandelier Exit +Channel,Price Channel +CI,Choppiness Index +CMF,Chaikin Money Flow +CMO,Chande Momentum Oscillator +CORREL,Pearson's Correlation Coefficient +CRSI,ConnorsRSI +DC,Donchian Channels +DCP,Dominant Cycle Periods +DEMA,Double Exponential Moving Average +DMI,Directional Movement Index +DPO,Detrended Price Oscillator +DX,Directional Movement Index +EMA,Exponential Moving Average +EPMA,Endpoint Moving Average +ERI,Elder-ray Index +FCB,Fractal Chaos Bands +FI,Force Index +GO,Gator Oscillator +HE,Hurst Exponent +HMA,Hull Moving Average +HT_TRENDLINE,Hilbert Transform - Instantaneous Trendline +HT_TRENDMODE,Hilbert Transform - Trend vs Cycle Mode +HV,Historical Volatility +IC,Ichimoku Cloud +KAMA,Kaufman Adaptive Moving Average +KDJ,KDJ Index +Keltner,Keltner Channel +KVO,Klinger Volume Oscillator +LINEARREG,Linear Regression +LINEARREG_ANGLE,Linear Regression Angle +LINEARREG_INTERCEPT,Linear Regression Intercept +LINEARREG_SLOPE,Linear Regression Slope +LSMA,Least Squares Moving Average +LWMA,Linearly Weighted Moving Average +MACDEXT,MACD with controllable MA type +MACDFIX,Moving Average Convergence Divergence Fix 12/26 +MAD,Mean absolute deviation +MAE,Moving Average Envelope +MAMA,MESA Adaptive Moving Average +MAPE,Mean absolute percentage error +MAX,Highest value over a specified period +MAXINDEX,Index of highest value over a specified period +MD,McGinley Dynamic +MEDPRICE,Median Price +MFI,Money Flow Index +MIN,Lowest value over a specified period +MININDEX,Index of lowest value over a specified period +MINMAX,Lowest and highest values over a specified period +MINMAXINDEX,Indexes of lowest and highest values over a period +MMA,Modified Moving Average +MOM,Momentum +MSE,Mean square error +NATR,Normalized Average True Range +OBV,On Balance Volume +OsMA,Moving Average of Oscillator +PAZ,Price Action Zones +Pivots,Pivots +PMO,Price Momentum Oscillator +PP,Pivot Points +PPO,Percentage Price Oscillator +PPMA,Pivot Point Moving Average +PRS,Price Relative Strength +PVI,Positive Volume Index +PVO,Percentage Volume Oscillator +Qstick,Qstick Indicator +R2,R-Squared (Coefficient of Determination) +Regression,Regression Line Indicator +RLW,%R Larry Williams +RMA,Running Moving Average +ROC,Rate of Change +ROCB,ROC with Bands +RPP,Rolling Pivot Points +RRA,Rescaled Range Analysis +RSI,Relative Strength Index +SAR,Parabolic SAR +SAREXT,Parabolic SAR - Extended +SDC,Standard Deviation Channels +SI,Swing Index +SLR,Slope and Linear Regression +SMA,Simple Moving Average +SMI,Stochastic Momentum Index +SMMA,Smoothed Moving Average +ST,SuperTrend +STARC,STARC Bands +STC,Schaff Trend Cycle +STDDEV,Standard Deviation +STOCH,Stochastic +STOCHF,Stochastic Fast +STOCHRSI,Stochastic Relative Strength Index +SUM,Summation +T3,Triple Exponential Moving Average (T3) +TEMA,Triple Exponential Moving Average +TRANGE,True Range +TRIMA,Triangular Moving Average +TRIX,1-day Rate-Of-Change (ROC) of a Triple Smooth EMA +TSI,True Strength Index +TYPPRICE,Typical Price +UI,Ulcer Index +ULTOSC,Ultimate Oscillator +VAR,Variance +VI,Vortex Indicator +Volume,Volume Indicator +VS,Volatility Stop +VWAP,Volume Weighted Average Price +VWMA,Volume Weighted Moving Average +WA,Williams Alligator +WCLPRICE,Weighted Close Price +WF,Williams Fractal +WMA,Weighted Moving Average +ZS,Z-Score +ZZ,ZigZag Indicator diff --git a/docs/Progress.md b/docs/Progress.md index 793f488..eaf705a 100644 --- a/docs/Progress.md +++ b/docs/Progress.md @@ -1,5 +1,313 @@ -# Backlog and done - -|**QT**|**Chart**|Cmnt|Docs|isNew|Validation| -|--|:--:|:--:|:--:|:--:|:--:| -|AFIRMA|✔️||||| \ No newline at end of file +| AD | Chaikin A/D Line | +| AROON | Aroon Indicator | +| ADX | Average Directional Movement Index | +| ADXR | Average Directional Movement Index Rating | +| DX | Directional Movement Index | +| SAR | Parabolic SAR | +| SAREXT | Parabolic SAR - Extended | +| HT_TRENDLINE | Hilbert Transform - Instantaneous Trendline | +| HT_TRENDMODE | Hilbert Transform - Trend vs Cycle Mode | +| ZZ | ZigZag Indicator | +| DMI | Directional Movement Index | +| Alligator | Alligator Indicator | +| Regression | Regression Line Indicator | +| SI | Swing Index | +| ATS | ATR Trailing Stop | +| ERI | Elder-ray Index | +| GO | Gator Oscillator | +| HE | Hurst Exponent | +| IC | Ichimoku Cloud | +| ST | SuperTrend | +| VI | Vortex Indicator | +| WA | Williams Alligator | +| RSI | Relative Strength Index | +| CCI | Commodity Channel Index | +| MOM | Momentum | +| ROC | Rate of Change | +| PPO | Percentage Price Oscillator | +| AO | Awesome Oscillator | +| CMO | Chande Momentum Oscillator | +| TRIX | 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA | +| ULTOSC | Ultimate Oscillator | +| AROONOSC | Aroon Oscillator | +| ADOSC | Chaikin A/D Oscillator | +| APO | Absolute Price Oscillator | +| STOCH | Stochastic | +| STOCHF | Stochastic Fast | +| STOCHRSI | Stochastic Relative Strength Index | +| Qstick | Qstick Indicator | +| RLW | %R Larry Williams | +| AC | Acceleration Oscillator | +| TSI | True Strength Index | +| CRSI | ConnorsRSI | +| DPO | Detrended Price Oscillator | +| KDJ | KDJ Index | +| STC | Schaff Trend Cycle | +| SMI | Stochastic Momentum Index | +| BB | Bollinger Bands | +| Keltner | Keltner Channel | +| BBF | Bollinger Bands Flat | +| Channel | Price Channel | +| MAE | Moving Average Envelope | +| PAZ | Price Action Zones | +| DC | Donchian Channels | +| FCB | Fractal Chaos Bands | +| PP | Pivot Points | +| RPP | Rolling Pivot Points | +| STARC | STARC Bands | +| SDC | Standard Deviation Channels | +| OBV | On Balance Volume | +| PVI | Positive Volume Index | +| Volume | Volume Indicator | +| MFI | Money Flow Index | +| ADL | Accumulation / Distribution Line | +| CMF | Chaikin Money Flow | +| FI | Force Index | +| KVO | Klinger Volume Oscillator | +| PVO | Percentage Volume Oscillator | +| ATS | ATR Trailing Stop | +| CE | Chandelier Exit | +| SAR | Parabolic SAR | +| ST | SuperTrend | +| VS | Volatility Stop | +| Pivots | Pivots | +| WF | Williams Fractal | +| EMA | Exponential Moving Average | +| SMA | Simple Moving Average | +| LWMA | Linearly Weighted Moving Average | +| SMMA | Smoothed Moving Average | +| MMA | Modified Moving Average | +| KAMA | Kaufman Adaptive Moving Average | +| DEMA | Double Exponential Moving Average | +| TEMA | Triple Exponential Moving Average | +| MAMA | MESA Adaptive Moving Average | +| TRIMA | Triangular Moving Average | +| T3 | Triple Exponential Moving Average (T3) | +| PPMA | Pivot Point Moving Average | +| WMA | Weighted Moving Average | +| ALMA | Arnaud Legoux Moving Average | +| EPMA | Endpoint Moving Average | +| HMA | Hull Moving Average | +| LSMA | Least Squares Moving Average | +| MD | McGinley Dynamic | +| RMA | Running Moving Average | +| VWAP | Volume Weighted Average Price | +| VWMA | Volume Weighted Moving Average | +| ATR | Average True Range | +| NATR | Normalized Average True Range | +| TRANGE | True Range | +| STDDEV | Standard Deviation | +| HV | Historical Volatility | +| BOP | Balance of Power | +| BBP | Bull and Bear Power | +| CI | Choppiness Index | +| DCP | Dominant Cycle Periods | +| PMO | Price Momentum Oscillator | +| PRS | Price Relative Strength | +| ROCB | ROC with Bands | +| RRA | Rescaled Range Analysis | +| UI | Ulcer Index | +| CORREL | Pearson's Correlation Coefficient | +| BETA | Beta | +| VAR | Variance | +| AVGPRICE | Average Price | +| MEDPRICE | Median Price | +| TYPPRICE | Typical Price | +| WCLPRICE | Weighted Close Price | +| SUM | Summation | +| MAX | Highest value over a specified period | +| MIN | Lowest value over a specified period | +| MAXINDEX | Index of highest value over a specified period | +| MININDEX | Index of lowest value over a specified period | +| MINMAX | Lowest and highest values over a specified period | +| MINMAXINDEX | Indexes of lowest and highest values over a period | +| BC | Beta Coefficient | +| MAD | Mean absolute deviation | +| MAPE | Mean absolute percentage error | +| MSE | Mean square error | +| R2 | R-Squared (Coefficient of Determination) | +| SLR | Slope and Linear Regression | +| ZS | Z-Score | +| AD | Chaikin A/D Line | +| AROON | Aroon Indicator | +| ADX | Average Directional Movement Index | +| ADXR | Average Directional Movement Index Rating | +| DX | Directional Movement Index | +| SAR | Parabolic SAR | +| SAREXT | Parabolic SAR - Extended | +| HT_TRENDLINE | Hilbert Transform - Instantaneous Trendline | +| HT_TRENDMODE | Hilbert Transform - Trend vs Cycle Mode | +| ZZ | ZigZag Indicator | +| DMI | Directional Movement Index | +| Alligator | Alligator Indicator | +| Regression | Regression Line Indicator | +| SI | Swing Index | +| ATS | ATR Trailing Stop | +| ERI | Elder-ray Index | +| GO | Gator Oscillator | +| HE | Hurst Exponent | +| IC | Ichimoku Cloud | +| ST | SuperTrend | +| VI | Vortex Indicator | +| WA | Williams Alligator | +| RSI | Relative Strength Index | +| CCI | Commodity Channel Index | +| MOM | Momentum | +| ROC | Rate of Change | +| PPO | Percentage Price Oscillator | +| AO | Awesome Oscillator | +| CMO | Chande Momentum Oscillator | +| TRIX | 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA | +| ULTOSC | Ultimate Oscillator | +| AROONOSC | Aroon Oscillator | +| ADOSC | Chaikin A/D Oscillator | +| APO | Absolute Price Oscillator | +| STOCH | Stochastic | +| STOCHF | Stochastic Fast | +| STOCHRSI | Stochastic Relative Strength Index | +| Qstick | Qstick Indicator | +| RLW | %R Larry Williams | +| AC | Acceleration Oscillator | +| TSI | True Strength Index | +| CRSI | ConnorsRSI | +| DPO | Detrended Price Oscillator | +| KDJ | KDJ Index | +| STC | Schaff Trend Cycle | +| SMI | Stochastic Momentum Index | +| BB | Bollinger Bands | +| Keltner | Keltner Channel | +| BBF | Bollinger Bands Flat | +| Channel | Price Channel | +| MAE | Moving Average Envelope | +| PAZ | Price Action Zones | +| DC | Donchian Channels | +| FCB | Fractal Chaos Bands | +| PP | Pivot Points | +| RPP | Rolling Pivot Points | +| STARC | STARC Bands | +| SDC | Standard Deviation Channels | +| OBV | On Balance Volume | +| PVI | Positive Volume Index | +| Volume | Volume Indicator | +| MFI | Money Flow Index | +| ADL | Accumulation / Distribution Line | +| CMF | Chaikin Money Flow | +| FI | Force Index | +| KVO | Klinger Volume Oscillator | +| PVO | Percentage Volume Oscillator | +| ATS | ATR Trailing Stop | +| CE | Chandelier Exit | +| SAR | Parabolic SAR | +| ST | SuperTrend | +| VS | Volatility Stop | +| Pivots | Pivots | +| WF | Williams Fractal | +| ALMA | Arnaud Legoux Moving Average | +| EPMA | Endpoint Moving Average | +| HMA | Hull Moving Average | +| LSMA | Least Squares Moving Average | +| MD | McGinley Dynamic | +| RMA | Running Moving Average | +| T3 | Tillson T3 Moving Average | +| VWAP | Volume Weighted Average Price | +| VWMA | Volume Weighted Moving Average | +| BOP | Balance of Power | +| BBP | Bull and Bear Power | +| CI | Choppiness Index | +| DCP | Dominant Cycle Periods | +| PMO | Price Momentum Oscillator | +| PRS | Price Relative Strength | +| ROCB | ROC with Bands | +| RRA | Rescaled Range Analysis | +| UI | Ulcer Index | +| BC | Beta Coefficient | +| MAD | Mean absolute deviation | +| MAPE | Mean absolute percentage error | +| MSE | Mean square error | +| R2 | R-Squared (Coefficient of Determination) | +| SLR | Slope and Linear Regression | +| ZS | Z-Score | +| EMA | Exponential Moving Average | +| SMA | Simple Moving Average | +| LWMA | Linearly Weighted Moving Average | +| SMMA | Smoothed Moving Average | +| MMA | Modified Moving Average | +| KAMA | Kaufman Adaptive Moving Average | +| DEMA | Double Exponential Moving Average | +| TEMA | Triple Exponential Moving Average | +| MAMA | MESA Adaptive Moving Average | +| TRIMA | Triangular Moving Average | +| T3 | Triple Exponential Moving Average (T3) | +| PPMA | Pivot Point Moving Average | +| MAE | Moving Average Envelope | +| MACD | Moving Average Convergence Divergence | +| MACDEXT | MACD with controllable MA type | +| MACDFIX | Moving Average Convergence Divergence Fix 12/26 | +| OsMA | Moving Average of Oscillator | +| Regression | Regression Indicator | +| LINEARREG | Linear Regression | +| LINEARREG_ANGLE | Linear Regression Angle | +| LINEARREG_INTERCEPT | Linear Regression Intercept | +| LINEARREG_SLOPE | Linear Regression Slope | +| RSI | Relative Strength Index | +| CCI | Commodity Channel Index | +| MOM | Momentum | +| ROC | Rate of Change | +| PPO | Percentage Price Oscillator | +| AO | Awesome Oscillator | +| CMO | Chande Momentum Oscillator | +| TRIX | 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA | +| ULTOSC | Ultimate Oscillator | +| AROONOSC | Aroon Oscillator | +| ADOSC | Chaikin A/D Oscillator | +| APO | Absolute Price Oscillator | +| STOCH | Stochastic | +| STOCHF | Stochastic Fast | +| STOCHRSI | Stochastic Relative Strength Index | +| Qstick | Qstick Indicator | +| RLW | %R Larry Williams | +| AC | Acceleration Oscillator | +| TSI | True Strength Index | +| AD | Chaikin A/D Line | +| AROON | Aroon Indicator | +| ADX | Average Directional Movement Index | +| ADXR | Average Directional Movement Index Rating | +| DX | Directional Movement Index | +| SAR | Parabolic SAR | +| SAREXT | Parabolic SAR - Extended | +| HT_TRENDLINE | Hilbert Transform - Instantaneous Trendline | +| HT_TRENDMODE | Hilbert Transform - Trend vs Cycle Mode | +| ZZ | ZigZag Indicator | +| DMI | Directional Movement Index | +| Alligator | Alligator Indicator | +| Regression | Regression Line Indicator | +| SI | Swing Index | +| ATR | Average True Range | +| NATR | Normalized Average True Range | +| TRANGE | True Range | +| STDDEV | Standard Deviation | +| HV | Historical Volatility | +| BB | Bollinger Bands | +| Keltner | Keltner Channel | +| BBF | Bollinger Bands Flat | +| Channel | Price Channel | +| MAE | Moving Average Envelope | +| PAZ | Price Action Zones | +| OBV | On Balance Volume | +| PVI | Positive Volume Index | +| Volume | Volume Indicator | +| MFI | Money Flow Index | +| CORREL | Pearson's Correlation Coefficient | +| BETA | Beta | +| VAR | Variance | +| AVGPRICE | Average Price | +| MEDPRICE | Median Price | +| TYPPRICE | Typical Price | +| WCLPRICE | Weighted Close Price | +| SUM | Summation | +| MAX | Highest value over a specified period | +| MIN | Lowest value over a specified period | +| MAXINDEX | Index of highest value over a specified period | +| MININDEX | Index of lowest value over a specified period | +| MINMAX | Lowest and highest values over a specified period | +| MINMAXINDEX | Indexes of lowest and highest values over a period | diff --git a/docs/_sidebar.md b/docs/_sidebar.md index cc1650b..5df2cf7 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -1,7 +1,34 @@ -* [QuanTAlib](/) + +* [Home](/) +* Introduction + * [Overview]() + * [Features]() * [Historical vs Real-time analysis](essays/realtime.md) -* [Indicators](indicators/indicators.md) - * Averages & Trends + +* Core Concepts + * [Time Series Data Handling]() + * [Calculation classes]() + * [Presentation Classes]() + +* QuanTAlib C# Library + * [Installation]() + * [Quick Start Guide]() + * [Usage Examples]() + * [Tests and Validation]() + +* Quantower Charts + * [Installation]() + * [Quick Start Guide]() + * [Using VS Code for QuanTower coding](setup/vscode.md) + * [Using DotPeek](setup/dotpeek.md) + * [Creating Custom Indicators]() + * [Inspecting Quantower Internals]() + +* [Available Indicators](indicators/indicators.md) + * Basic Transforms + * Numerical Analysis + * Errors + * Moving Averages * [AFIRMA - Adaptive Filtering Integrated Recursive Moving Average](indicators/averages/afirma/afirma.md) * [Calculation](indicators/averages/afirma/calc.md) * [Analysis](indicators/averages/afirma/analysis.md) @@ -14,7 +41,6 @@ * [Calculation](indicators/averages/ama/calc.md) * [Analysis](indicators/averages/ama/analysis.md) * [Charts](indicators/averages/ama/charts.md) - * [Convolutiuon] * [DEMA - Double Exponential Moving Average](indicators/averages/dema/dema.md) * [Calculation](indicators/averages/dema/calc.md) * [Analysis](indicators/averages/dema/analysis.md) @@ -61,11 +87,9 @@ * VIDYA - Variable Index Dynamic Average * WMA - Weighted Moving Average * ZLEMA - Weighted Moving Average - * Basic Data Transforms - * [Statistics & Numerical Analysis](indicators/statistics/list.md) + * Trends + * Momentum + * Oscillators * Volatility * Volume - * Momentum & Oscillators -* Development - * [VS Code](setup/vscode.md) - * [DotPeek](setup/dotpeek.md) + diff --git a/docs/index.html b/docs/index.html index 4c1158b..c98425e 100644 --- a/docs/index.html +++ b/docs/index.html @@ -2,76 +2,38 @@ - Document + QuanTAlib Documentation - + - - - - +
- - - - - - - + + + + + + - \ No newline at end of file + diff --git a/docs/styles.css b/docs/styles.css new file mode 100644 index 0000000..7b7c45a --- /dev/null +++ b/docs/styles.css @@ -0,0 +1,1602 @@ +:root { + /* Base Styles */ + box-sizing: border-box; + background-color: var(--base-background-color); + font-size: var(--base-font-size); + font-weight: var(--base-font-weight); + line-height: var(--base-line-height); + letter-spacing: var(--base-letter-spacing); + color: var(--base-color); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + /* Base Colors */ + --mono-hue: 201; + --mono-saturation: 18%; + --mono-shade3: hsl(var(--mono-hue), var(--mono-saturation), 13%); + --mono-shade2: hsl(var(--mono-hue), var(--mono-saturation), 15%); + --mono-shade1: hsl(var(--mono-hue), var(--mono-saturation), 17%); + --mono-base: hsl(var(--mono-hue), var(--mono-saturation), 19%); + --mono-tint1: hsl(var(--mono-hue), var(--mono-saturation), 25%); + --mono-tint2: hsl(var(--mono-hue), var(--mono-saturation), 35%); + --mono-tint3: hsl(var(--mono-hue), var(--mono-saturation), 43%); + + /* Theme Colors */ + --theme-hue: 204; + --theme-saturation: 90%; + --theme-lightness: 45%; + --theme-color: hsl(var(--theme-hue), var(--theme-saturation), var(--theme-lightness)); + + /* Base Variables */ + --base-background-color: var(--mono-base); + --base-color: #d3d3d3; + --base-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + --base-font-size: 16px; + --base-font-weight: normal; + --base-line-height: 1.7; + + /* Modular Scale */ + --modular-scale: 1.333; + --modular-scale--2: calc(var(--modular-scale--1) / var(--modular-scale)); + --modular-scale--1: calc(var(--modular-scale-1) / var(--modular-scale)); + --modular-scale-1: 1rem; + --modular-scale-2: calc(var(--modular-scale-1) * var(--modular-scale)); + --modular-scale-3: calc(var(--modular-scale-2) * var(--modular-scale)); + --modular-scale-4: calc(var(--modular-scale-3) * var(--modular-scale)); + --modular-scale-5: calc(var(--modular-scale-4) * var(--modular-scale)); + + /* Font Sizes */ + --font-size-xxxl: var(--modular-scale-5); + --font-size-xxl: var(--modular-scale-4); + --font-size-xl: var(--modular-scale-3); + --font-size-l: var(--modular-scale-2); + --font-size-m: var(--modular-scale-1); + --font-size-s: var(--modular-scale--1); + --font-size-xs: var(--modular-scale--2); + + /* Headings */ + --heading-color: #fff; + --heading-font-weight: var(--strong-font-weight); + --heading-margin: 2.5rem 0 0; + --heading-h1-font-size: var(--font-size-xxl); + --heading-h2-font-size: var(--font-size-xl); + --heading-h3-font-size: var(--font-size-l); + --heading-h4-font-size: var(--font-size-m); + --heading-h5-font-size: var(--font-size-s); + --heading-h6-font-size: var(--font-size-xs); + + /* Blockquote */ + --blockquote-background: var(--mono-shade2); + --blockquote-border-color: var(--theme-color); + --blockquote-border-style: solid; + --blockquote-border-width: 0 0 0 4px; + --blockquote-border-radius: 0 var(--border-radius-m) var(--border-radius-m) 0; + --blockquote-padding: 1.5em; + + /* Code */ + --code-font-family: Inconsolata, Consolas, Menlo, Monaco, "Andale Mono WT", "Andale Mono", "Lucida Console", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace; + --code-font-size: calc(var(--font-size-m) * 0.95); + --code-font-weight: normal; + --code-tab-size: 4; + --code-block-border-radius: var(--border-radius-m); + --code-block-padding: 1.75em 1.5em 1.5em 1.5em; + --code-inline-background: var(--mono-tint1); + --code-inline-border-radius: var(--border-radius-s); + --code-inline-padding: 0.125em 0.4em; + + /* Notice */ + --notice-background: var(--mono-shade2); + --notice-border-radius: 0 var(--border-radius-m) var(--border-radius-m) 0; + --notice-border-width: 0 0 0 4px; + --notice-padding: 1em 1.5em 1em 3em; + + /* Table */ + --table-cell-border-color: var(--mono-tint1); + --table-cell-border-width: 1px 0; + --table-cell-padding: 0.75em 0.5em; + --table-row-odd-background: var(--mono-shade2); + + /* Layout */ + --content-max-width: 55em; + + /* Cover */ + --cover-margin: 0 auto; + --cover-max-width: 40em; + --cover-background-color: var(--base-background-color); + --cover-background-image: radial-gradient(ellipse at center bottom, var(--mono-tint3), transparent); + + /* Navbar */ + --navbar-menu-background: var(--mono-tint1); + --navbar-menu-border-radius: var(--border-radius-m); + --navbar-menu-padding: 0.5em; + + /* Sidebar */ + --sidebar-background: var(--mono-shade1); + --sidebar-border-color: var(--mono-tint1); + --sidebar-border-width: 0 1px 0 0; + --sidebar-padding: 0 25px; + --sidebar-width: 17rem; + + /* Search */ + --search-margin: 1.5rem 0 0; + --search-input-background-color: var(--mono-shade2); + --search-input-border-color: var(--mono-tint1); + --search-input-padding: 0.5em; + + /* Misc UI */ + --border-radius-s: 2px; + --border-radius-m: 4px; + --duration-fast: 0.25s; + --duration-medium: 0.5s; + --duration-slow: 1s; +} + +.github-corner{ + position:absolute; + z-index:40; + top:0; + right:0; + border-bottom:0; + text-decoration:none +} +.github-corner svg{ + height:70px; + width:70px; + fill:var(--theme-color); + color:var(--base-background-color) +} +.github-corner:hover .octo-arm{ + -webkit-animation:octocat-wave 560ms ease-in-out; + animation:octocat-wave 560ms ease-in-out +} +@-webkit-keyframes octocat-wave{ + 0%,100%{ + transform:rotate(0) + } + 20%,60%{ + transform:rotate(-25deg) + } + 40%,80%{ + transform:rotate(10deg) + } +} +@keyframes octocat-wave{ + 0%,100%{ + transform:rotate(0) + } + 20%,60%{ + transform:rotate(-25deg) + } + 40%,80%{ + transform:rotate(10deg) + } +} +.progress{ + position:fixed; + z-index:2147483647; + top:0; + left:0; + right:0; + height:3px; + width:0; + background-color:var(--theme-color); + transition:width var(--duration-fast),opacity calc(var(--duration-fast)*2) +} +body.ready-transition:after,body.ready-transition>*:not(.progress){ + opacity:0; + transition:opacity var(--spinner-transition-duration) +} +body.ready-transition:after{ + content:""; + position:absolute; + z-index:1000; + top:calc(50% - var(--spinner-size)/2); + left:calc(50% - var(--spinner-size)/2); + height:var(--spinner-size); + width:var(--spinner-size); + border:var(--spinner-track-width, 0) solid var(--spinner-track-color); + border-left-color:var(--theme-color); + border-radius:50%; + -webkit-animation:spinner var(--duration-slow) infinite linear; + animation:spinner var(--duration-slow) infinite linear +} +body.ready-transition.ready-spinner:after{ + opacity:1 +} +body.ready-transition.ready-fix:after{ + opacity:0 +} +body.ready-transition.ready-fix>*:not(.progress){ + opacity:1; + transition-delay:var(--spinner-transition-duration) +} +@-webkit-keyframes spinner{ + 0%{ + transform:rotate(0deg) + } + 100%{ + transform:rotate(360deg) + } +} +@keyframes spinner{ + 0%{ + transform:rotate(0deg) + } + 100%{ + transform:rotate(360deg) + } +} +*,*:before,*:after{ + box-sizing:inherit; + font-size:inherit; + -webkit-overflow-scrolling:touch; + -webkit-tap-highlight-color:rgba(0,0,0,0); + -webkit-text-size-adjust:none; + -webkit-touch-callout:none +} +html,button,input,optgroup,select,textarea{ + font-family:var(--base-font-family) +} +button,input,optgroup,select,textarea{ + font-size:100%; + margin:0 +} +a{ + text-decoration:none; + -webkit-text-decoration-skip:ink; + text-decoration-skip-ink:auto +} +body{ + margin:0 +} +hr{ + height:0; + margin:2em 0; + border:none; + border-bottom:var(--hr-border, 0) +} +img{ + max-width:100%; + border:0 +} +main{ + display:block; + position:relative; + overflow-x:hidden; + min-height:100vh +} +main.hidden{ + display:none +} +mark{ + background:var(--mark-background); + color:var(--mark-color) +} +pre{ + font-family:var(--pre-font-family); + font-size:var(--pre-font-size); + font-weight:var(--pre-font-weight); + line-height:var(--pre-line-height) +} +small{ + display:inline-block; + font-size:var(--small-font-size) +} +strong{ + font-weight:var(--strong-font-weight); + color:var(--strong-color, currentColor) +} +sub,sup{ + font-size:var(--subsup-font-size); + line-height:0; + position:relative; + vertical-align:baseline +} +sub{ + bottom:-0.25em +} +sup{ + top:-0.5em +} +body:not([data-platform^=Mac]) *{ + scrollbar-color:hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.3) hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.1); + scrollbar-width:thin +} +body:not([data-platform^=Mac]) * ::-webkit-scrollbar{ + width:5px; + height:5px +} +body:not([data-platform^=Mac]) * ::-webkit-scrollbar-thumb{ + background:hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.3) +} +body:not([data-platform^=Mac]) * ::-webkit-scrollbar-track{ + background:hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.1) +} +::-moz-selection{ + background:var(--selection-color) +} +::selection{ + background:var(--selection-color) +} +.emoji{ + height:var(--emoji-size); + vertical-align:middle +} +.task-list-item{ + list-style:none +} +.task-list-item input{ + margin-right:.5em; + margin-left:0; + vertical-align:.075em +} +.markdown-section code[class*=lang-],.markdown-section pre[data-lang]{ + font-family:var(--code-font-family); + font-size:var(--code-font-size); + font-weight:var(--code-font-weight); + letter-spacing:normal; + line-height:var(--code-block-line-height); + -moz-tab-size:var(--code-tab-size); + -o-tab-size:var(--code-tab-size); + tab-size:var(--code-tab-size); + text-align:left; + white-space:pre; + word-spacing:normal; + word-wrap:normal; + word-break:normal; + -webkit-hyphens:none; + hyphens:none +} +.markdown-section pre[data-lang]{ + position:relative; + overflow:hidden; + margin:var(--code-block-margin); + padding:0; + border-radius:var(--code-block-border-radius) +} +.markdown-section pre[data-lang]::after{ + content:attr(data-lang); + position:absolute; + top:.75em; + right:.75em; + opacity:.6; + color:inherit; + font-size:var(--font-size-s); + line-height:1 +} +.markdown-section pre[data-lang] code{ + display:block; + overflow:auto; + padding:var(--code-block-padding) +} +code[class*=lang-],pre[data-lang]{ + color:var(--code-theme-text) +} +pre[data-lang]::-moz-selection,pre[data-lang] ::-moz-selection,code[class*=lang-]::-moz-selection,code[class*=lang-] ::-moz-selection{ + background:var(--code-theme-selection, var(--selection-color)) +} +pre[data-lang]::selection,pre[data-lang] ::selection,code[class*=lang-]::selection,code[class*=lang-] ::selection{ + background:var(--code-theme-selection, var(--selection-color)) +} +:not(pre)>code[class*=lang-],pre[data-lang]{ + background:var(--code-theme-background) +} +.namespace{ + opacity:.7 +} +.token.comment,.token.prolog,.token.doctype,.token.cdata{ + color:var(--code-theme-comment) +} +.token.punctuation{ + color:var(--code-theme-punctuation) +} +.token.property,.token.tag,.token.boolean,.token.number,.token.constant,.token.symbol,.token.deleted{ + color:var(--code-theme-tag) +} +.token.selector,.token.attr-name,.token.string,.token.char,.token.builtin,.token.inserted{ + color:var(--code-theme-selector) +} +.token.operator,.token.entity,.token.url,.language-css .token.string,.style .token.string{ + color:var(--code-theme-operator) +} +.token.atrule,.token.attr-value,.token.keyword{ + color:var(--code-theme-keyword) +} +.token.function{ + color:var(--code-theme-function) +} +.token.regex,.token.important,.token.variable{ + color:var(--code-theme-variable) +} +.token.important,.token.bold{ + font-weight:bold +} +.token.italic{ + font-style:italic +} +.token.entity{ + cursor:help +} +.markdown-section{ + position:relative; + max-width:var(--content-max-width); + margin:0 auto; + padding:2rem 45px +} +.app-nav:not(:empty)~main .markdown-section{ + padding-top:3.5rem +} +.markdown-section figure,.markdown-section p,.markdown-section ol,.markdown-section ul{ + margin:1em 0 +} +.markdown-section ol,.markdown-section ul{ + padding-left:1.5rem +} +.markdown-section ol ol,.markdown-section ol ul,.markdown-section ul ol,.markdown-section ul ul{ + margin-top:.15rem; + margin-bottom:.15rem +} +.markdown-section a{ + border-bottom:var(--link-border-bottom); + color:var(--link-color); + -webkit-text-decoration:var(--link-text-decoration); + text-decoration:var(--link-text-decoration); + -webkit-text-decoration-color:var(--link-text-decoration-color); + text-decoration-color:var(--link-text-decoration-color) +} +.markdown-section a:hover{ + border-bottom:var(--link-border-bottom--hover, var(--link-border-bottom, 0)); + color:var(--link-color--hover, var(--link-color)); + -webkit-text-decoration:var(--link-text-decoration--hover, var(--link-text-decoration)); + text-decoration:var(--link-text-decoration--hover, var(--link-text-decoration)); + -webkit-text-decoration-color:var(--link-text-decoration-color--hover, var(--link-text-decoration-color)); + text-decoration-color:var(--link-text-decoration-color--hover, var(--link-text-decoration-color)) +} +.markdown-section a.anchor{ + border-bottom:0; + color:inherit; + text-decoration:none +} +.markdown-section a.anchor:hover{ + text-decoration:underline +} +.markdown-section blockquote{ + overflow:visible; + margin:2em 0; + padding:var(--blockquote-padding); + border-width:var(--blockquote-border-width, 0); + border-style:var(--blockquote-border-style); + border-color:var(--blockquote-border-color); + border-radius:var(--blockquote-border-radius); + background:var(--blockquote-background); + color:var(--blockquote-color); + font-family:var(--blockquote-font-family); + font-size:var(--blockquote-font-size); + font-style:var(--blockquote-font-style); + font-weight:var(--blockquote-font-weight); + quotes:"“" "”" "‘" "’" +} +.markdown-section blockquote em{ + font-family:var(--blockquote-em-font-family); + font-size:var(--blockquote-em-font-size); + font-style:var(--blockquote-em-font-style); + font-weight:var(--blockquote-em-font-weight) +} +.markdown-section blockquote p:first-child{ + margin-top:0 +} +.markdown-section blockquote p:first-child:before,.markdown-section blockquote p:first-child:after{ + color:var(--blockquote-quotes-color); + font-family:var(--blockquote-quotes-font-family); + font-size:var(--blockquote-quotes-font-size); + line-height:0 +} +.markdown-section blockquote p:first-child:before{ + content:var(--blockquote-quotes-open); + margin-right:.15em; + vertical-align:-0.45em +} +.markdown-section blockquote p:first-child:after{ + content:var(--blockquote-quotes-close); + margin-left:.15em; + vertical-align:-0.55em +} +.markdown-section blockquote p:last-child{ + margin-bottom:0 +} +.markdown-section code{ + font-family:var(--code-font-family); + font-size:var(--code-font-size); + font-weight:var(--code-font-weight); + line-height:inherit +} +.markdown-section code:not([class*=lang-]):not([class*=language-]){ + margin:var(--code-inline-margin); + padding:var(--code-inline-padding); + border-radius:var(--code-inline-border-radius); + background:var(--code-inline-background); + color:var(--code-inline-color, currentColor); + white-space:nowrap +} +.markdown-section h1:first-child,.markdown-section h2:first-child,.markdown-section h3:first-child,.markdown-section h4:first-child,.markdown-section h5:first-child,.markdown-section h6:first-child{ + margin-top:0 +} +.markdown-section h1 a[data-id],.markdown-section h2 a[data-id],.markdown-section h3 a[data-id],.markdown-section h4 a[data-id],.markdown-section h5 a[data-id],.markdown-section h6 a[data-id]{ + display:inline-block +} +.markdown-section h1 code,.markdown-section h2 code,.markdown-section h3 code,.markdown-section h4 code,.markdown-section h5 code,.markdown-section h6 code{ + font-size:.875em +} +.markdown-section h1+h2,.markdown-section h1+h3,.markdown-section h1+h4,.markdown-section h1+h5,.markdown-section h1+h6,.markdown-section h2+h3,.markdown-section h2+h4,.markdown-section h2+h5,.markdown-section h2+h6,.markdown-section h3+h4,.markdown-section h3+h5,.markdown-section h3+h6,.markdown-section h4+h5,.markdown-section h4+h6,.markdown-section h5+h6{ + margin-top:1rem +} +.markdown-section h1{ + margin:var(--heading-h1-margin, var(--heading-margin)); + padding:var(--heading-h1-padding, var(--heading-padding)); + border-width:var(--heading-h1-border-width, 0); + border-style:var(--heading-h1-border-style); + border-color:var(--heading-h1-border-color); + font-family:var(--heading-h1-font-family, var(--heading-font-family)); + font-size:var(--heading-h1-font-size); + font-weight:var(--heading-h1-font-weight, var(--heading-font-weight)); + line-height:var(--base-line-height); + color:var(--heading-h1-color, var(--heading-color)) +} +.markdown-section h2{ + margin:var(--heading-h2-margin, var(--heading-margin)); + padding:var(--heading-h2-padding, var(--heading-padding)); + border-width:var(--heading-h2-border-width, 0); + border-style:var(--heading-h2-border-style); + border-color:var(--heading-h2-border-color); + font-family:var(--heading-h2-font-family, var(--heading-font-family)); + font-size:var(--heading-h2-font-size); + font-weight:var(--heading-h2-font-weight, var(--heading-font-weight)); + line-height:var(--base-line-height); + color:var(--heading-h2-color, var(--heading-color)) +} +.markdown-section h3{ + margin:var(--heading-h3-margin, var(--heading-margin)); + padding:var(--heading-h3-padding, var(--heading-padding)); + border-width:var(--heading-h3-border-width, 0); + border-style:var(--heading-h3-border-style); + border-color:var(--heading-h3-border-color); + font-family:var(--heading-h3-font-family, var(--heading-font-family)); + font-size:var(--heading-h3-font-size); + font-weight:var(--heading-h3-font-weight, var(--heading-font-weight)); + color:var(--heading-h3-color, var(--heading-color)) +} +.markdown-section h4{ + margin:var(--heading-h4-margin, var(--heading-margin)); + padding:var(--heading-h4-padding, var(--heading-padding)); + border-width:var(--heading-h4-border-width, 0); + border-style:var(--heading-h4-border-style); + border-color:var(--heading-h4-border-color); + font-family:var(--heading-h4-font-family, var(--heading-font-family)); + font-size:var(--heading-h4-font-size); + font-weight:var(--heading-h4-font-weight, var(--heading-font-weight)); + color:var(--heading-h4-color, var(--heading-color)) +} +.markdown-section h5{ + margin:var(--heading-h5-margin, var(--heading-margin)); + padding:var(--heading-h5-padding, var(--heading-padding)); + border-width:var(--heading-h5-border-width, 0); + border-style:var(--heading-h5-border-style); + border-color:var(--heading-h5-border-color); + font-family:var(--heading-h5-font-family, var(--heading-font-family)); + font-size:var(--heading-h5-font-size); + font-weight:var(--heading-h5-font-weight, var(--heading-font-weight)); + color:var(--heading-h5-color, var(--heading-color)) +} +.markdown-section h6{ + margin:var(--heading-h6-margin, var(--heading-margin)); + padding:var(--heading-h6-padding, var(--heading-padding)); + border-width:var(--heading-h6-border-width, 0); + border-style:var(--heading-h6-border-style); + border-color:var(--heading-h6-border-color); + font-family:var(--heading-h6-font-family, var(--heading-font-family)); + font-size:var(--heading-h6-font-size); + font-weight:var(--heading-h6-font-weight, var(--heading-font-weight)); + color:var(--heading-h6-color, var(--heading-color)) +} +.markdown-section iframe{ + margin:1em 0 +} +.markdown-section img{ + max-width:100% +} +.markdown-section kbd{ + display:inline-block; + min-width:var(--kbd-min-width); + margin:var(--kbd-margin); + padding:var(--kbd-padding); + border:var(--kbd-border); + border-radius:var(--kbd-border-radius); + background:var(--kbd-background); + font-family:inherit; + font-size:var(--kbd-font-size); + text-align:center; + letter-spacing:0; + line-height:1; + color:var(--kbd-color) +} +.markdown-section kbd+kbd{ + margin-left:-0.15em +} +.markdown-section table{ + display:block; + overflow:auto; + margin:1rem 0; + border-spacing:0; + border-collapse:collapse +} +.markdown-section th,.markdown-section td{ + padding:var(--table-cell-padding) +} +.markdown-section th:not([align]){ + text-align:left +} +.markdown-section thead{ + border-color:var(--table-head-border-color); + border-style:solid; + border-width:var(--table-head-border-width, 0); + background:var(--table-head-background) +} +.markdown-section th{ + font-weight:var(--table-head-font-weight); + color:var(--strong-color) +} +.markdown-section td{ + border-color:var(--table-cell-border-color); + border-style:solid; + border-width:var(--table-cell-border-width, 0) +} +.markdown-section tbody{ + border-color:var(--table-body-border-color); + border-style:solid; + border-width:var(--table-body-border-width, 0) +} +.markdown-section tbody tr:nth-child(odd){ + background:var(--table-row-odd-background) +} +.markdown-section tbody tr:nth-child(even){ + background:var(--table-row-even-background) +} +.markdown-section>ul .task-list-item{ + margin-left:-1.25em +} +.markdown-section>ul .task-list-item .task-list-item{ + margin-left:0 +} +.markdown-section .table-wrapper{ + overflow-x:auto +} +.markdown-section .table-wrapper table{ + display:table; + width:100% +} +.markdown-section .table-wrapper td::before{ + display:none +} +@media(max-width: 30em){ + .markdown-section .table-wrapper tbody,.markdown-section .table-wrapper tr,.markdown-section .table-wrapper td{ + display:block + } + .markdown-section .table-wrapper th,.markdown-section .table-wrapper td{ + border:none + } + .markdown-section .table-wrapper thead{ + display:none + } + .markdown-section .table-wrapper tr{ + border-color:var(--table-cell-border-color); + border-style:solid; + border-width:var(--table-cell-border-width, 0); + padding:var(--table-cell-padding) + } + .markdown-section .table-wrapper tr:not(:last-child){ + border-bottom:0 + } + .markdown-section .table-wrapper td{ + padding:.15em 0 .15em 8em + } + .markdown-section .table-wrapper td::before{ + display:inline-block; + width:8em; + margin-left:-8em; + font-weight:bold; + text-align:left + } +} +.markdown-section .tip,.markdown-section .warn{ + position:relative; + margin:2em 0; + padding:var(--notice-padding); + border-width:var(--notice-border-width, 0); + border-style:var(--notice-border-style); + border-color:var(--notice-border-color); + border-radius:var(--notice-border-radius); + background:var(--notice-background); + font-family:var(--notice-font-family); + font-weight:var(--notice-font-weight); + color:var(--notice-color) +} +.markdown-section .tip:before,.markdown-section .warn:before{ + display:inline-block; + position:var(--notice-before-position, relative); + top:var(--notice-before-top); + left:var(--notice-before-left); + height:var(--notice-before-height); + width:var(--notice-before-width); + margin:var(--notice-before-margin); + padding:var(--notice-before-padding); + border-radius:var(--notice-before-border-radius); + line-height:var(--notice-before-line-height); + font-family:var(--notice-before-font-family); + font-size:var(--notice-before-font-size); + font-weight:var(--notice-before-font-weight); + text-align:center +} +.markdown-section .tip{ + border-width:var(--notice-important-border-width, var(--notice-border-width, 0)); + border-style:var(--notice-important-border-style, var(--notice-border-style)); + border-color:var(--notice-important-border-color, var(--notice-border-color)); + background:var(--notice-important-background, var(--notice-background)); + color:var(--notice-important-color, var(--notice-color)) +} +.markdown-section .tip:before{ + content:var(--notice-important-before-content, var(--notice-before-content)); + background:var(--notice-important-before-background, var(--notice-before-background)); + color:var(--notice-important-before-color, var(--notice-before-color)) +} +.markdown-section .warn{ + border-width:var(--notice-tip-border-width, var(--notice-border-width, 0)); + border-style:var(--notice-tip-border-style, var(--notice-border-style)); + border-color:var(--notice-tip-border-color, var(--notice-border-color)); + background:var(--notice-tip-background, var(--notice-background)); + color:var(--notice-tip-color, var(--notice-color)) +} +.markdown-section .warn:before{ + content:var(--notice-tip-before-content, var(--notice-before-content)); + background:var(--notice-tip-before-background, var(--notice-before-background)); + color:var(--notice-tip-before-color, var(--notice-before-color)) +} +.cover{ + display:none; + position:relative; + z-index:20; + min-height:100vh; + flex-direction:column; + align-items:center; + justify-content:center; + padding:calc(var(--cover-border-inset, 0px) + var(--cover-border-width, 0px)); + color:var(--cover-color); + text-align:var(--cover-text-align) +} +@media screen and (-ms-high-contrast: active),screen and (-ms-high-contrast: none){ + .cover{ + height:100vh + } +} +.cover:before,.cover:after{ + content:""; + position:absolute +} +.cover:before{ + top:0; + bottom:0; + left:0; + right:0; + background-blend-mode:var(--cover-background-blend-mode); + background-color:var(--cover-background-color); + background-image:var(--cover-background-image); + background-position:var(--cover-background-position); + background-repeat:var(--cover-background-repeat); + background-size:var(--cover-background-size) +} +.cover:after{ + top:var(--cover-border-inset, 0); + bottom:var(--cover-border-inset, 0); + left:var(--cover-border-inset, 0); + right:var(--cover-border-inset, 0); + border-width:var(--cover-border-width, 0); + border-style:solid; + border-color:var(--cover-border-color) +} +.cover a{ + border-bottom:var(--cover-link-border-bottom); + color:var(--cover-link-color); + -webkit-text-decoration:var(--cover-link-text-decoration); + text-decoration:var(--cover-link-text-decoration); + -webkit-text-decoration-color:var(--cover-link-text-decoration-color); + text-decoration-color:var(--cover-link-text-decoration-color) +} +.cover a:hover{ + border-bottom:var(--cover-link-border-bottom--hover, var(--cover-link-border-bottom)); + color:var(--cover-link-color--hover, var(--cover-link-color)); + -webkit-text-decoration:var(--cover-link-text-decoration--hover, var(--cover-link-text-decoration)); + text-decoration:var(--cover-link-text-decoration--hover, var(--cover-link-text-decoration)); + -webkit-text-decoration-color:var(--cover-link-text-decoration-color--hover, var(--cover-link-text-decoration-color)); + text-decoration-color:var(--cover-link-text-decoration-color--hover, var(--cover-link-text-decoration-color)) +} +.cover h1{ + color:var(--cover-heading-color); + position:relative; + margin:0; + font-size:var(--cover-heading-font-size); + font-weight:var(--cover-heading-font-weight); + line-height:1.2 +} +.cover h1 a,.cover h1 a:hover{ + display:block; + border-bottom:none; + color:inherit; + text-decoration:none +} +.cover h1 small{ + position:absolute; + bottom:0; + margin-left:.5em +} +.cover h1 span{ + font-size:calc(var(--cover-heading-font-size-min)*1px) +} +@media(min-width: 26em){ + .cover h1 span{ + font-size:calc(var(--cover-heading-font-size-min)*1px + (var(--cover-heading-font-size-max) - var(--cover-heading-font-size-min))*(100vw - 420px)/604) + } +} +@media(min-width: 64em){ + .cover h1 span{ + font-size:calc(var(--cover-heading-font-size-max)*1px) + } +} +.cover blockquote{ + margin:0; + color:var(--cover-blockquote-color); + font-size:var(--cover-blockquote-font-size) +} +.cover blockquote a{ + color:inherit +} +.cover ul{ + padding:0; + list-style-type:none +} +.cover .cover-main{ + position:relative; + z-index:1; + max-width:var(--cover-max-width); + margin:var(--cover-margin); + padding:0 45px +} +.cover .cover-main>p:last-child{ + margin:1.25em -0.25em +} +.cover .cover-main>p:last-child a{ + display:block; + margin:.375em .25em; + padding:var(--cover-button-padding); + border:var(--cover-button-border); + border-radius:var(--cover-button-border-radius); + box-shadow:var(--cover-button-box-shadow); + background:var(--cover-button-background); + text-align:center; + -webkit-text-decoration:var(--cover-button-text-decoration); + text-decoration:var(--cover-button-text-decoration); + -webkit-text-decoration-color:var(--cover-button-text-decoration-color); + text-decoration-color:var(--cover-button-text-decoration-color); + color:var(--cover-button-color); + white-space:nowrap; + transition:var(--cover-button-transition) +} +.cover .cover-main>p:last-child a:hover{ + border:var(--cover-button-border--hover, var(--cover-button-border)); + box-shadow:var(--cover-button-box-shadow--hover, var(--cover-button-box-shadow)); + background:var(--cover-button-background--hover, var(--cover-button-background)); + -webkit-text-decoration:var(--cover-button-text-decoration--hover, var(--cover-button-text-decoration)); + text-decoration:var(--cover-button-text-decoration--hover, var(--cover-button-text-decoration)); + -webkit-text-decoration-color:var(--cover-button-text-decoration-color--hover, var(--cover-button-text-decoration-color)); + text-decoration-color:var(--cover-button-text-decoration-color--hover, var(--cover-button-text-decoration-color)); + color:var(--cover-button-color--hover, var(--cover-button-color)) +} +.cover .cover-main>p:last-child a:first-child{ + border:var(--cover-button-primary-border, var(--cover-button-border)); + box-shadow:var(--cover-button-primary-box-shadow, var(--cover-button-box-shadow)); + background:var(--cover-button-primary-background, var(--cover-button-background)); + -webkit-text-decoration:var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration)); + text-decoration:var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration)); + -webkit-text-decoration-color:var(--cover-button-primary-text-decoration-color, var(--cover-button-text-decoration-color)); + text-decoration-color:var(--cover-button-primary-text-decoration-color, var(--cover-button-text-decoration-color)); + color:var(--cover-button-primary-color, var(--cover-button-color)) +} +.cover .cover-main>p:last-child a:first-child:hover{ + border:var(--cover-button-primary-border--hover, var(--cover-button-border--hover, var(--cover-button-primary-border, var(--cover-button-border)))); + box-shadow:var(--cover-button-primary-box-shadow--hover, var(--cover-button-box-shadow--hover, var(--cover-button-primary-box-shadow, var(--cover-button-box-shadow)))); + background:var(--cover-button-primary-background--hover, var(--cover-button-background--hover, var(--cover-button-primary-background, var(--cover-button-background)))); + -webkit-text-decoration:var(--cover-button-primary-text-decoration--hover, var(--cover-button-text-decoration--hover, var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration)))); + text-decoration:var(--cover-button-primary-text-decoration--hover, var(--cover-button-text-decoration--hover, var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration)))); + -webkit-text-decoration-color:var(--cover-button-primary-text-decoration-color--hover, var(--cover-button-text-decoration-color--hover, var(--cover-button-primary-text-decoration-color, var(--cover-button-text-decoration-color)))); + text-decoration-color:var(--cover-button-primary-text-decoration-color--hover, var(--cover-button-text-decoration-color--hover, var(--cover-button-primary-text-decoration-color, var(--cover-button-text-decoration-color)))); + color:var(--cover-button-primary-color--hover, var(--cover-button-color--hover, var(--cover-button-primary-color, var(--cover-button-color)))) +} +@media(min-width: 30.01em){ + .cover .cover-main>p:last-child a{ + display:inline-block + } +} +.cover .mask{ + visibility:var(--cover-background-mask-visibility, hidden); + position:absolute; + top:0; + bottom:0; + left:0; + right:0; + background-color:var(--cover-background-mask-color); + opacity:var(--cover-background-mask-opacity) +} +.cover.has-mask .mask{ + visibility:visible +} +.cover.show{ + display:flex +} +.app-nav{ + position:absolute; + z-index:30; + top:calc(35px - .5em*var(--base-line-height)); + left:45px; + right:80px; + text-align:right +} +.app-nav.no-badge{ + right:45px +} +.app-nav li>img,.app-nav li>a>img{ + margin-top:-0.25em; + vertical-align:middle +} +.app-nav li>img:first-child,.app-nav li>a>img:first-child{ + margin-right:.5em +} +.app-nav ul,.app-nav li{ + margin:0; + padding:0; + list-style:none +} +.app-nav li{ + position:relative +} +.app-nav li a{ + display:block; + line-height:1; + transition:var(--navbar-root-transition) +} +.app-nav>ul>li{ + display:inline-block; + margin:var(--navbar-root-margin) +} +.app-nav>ul>li:first-child{ + margin-left:0 +} +.app-nav>ul>li:last-child{ + margin-right:0 +} +.app-nav>ul>li>a,.app-nav>ul>li>span{ + padding:var(--navbar-root-padding); + border-width:var(--navbar-root-border-width, 0); + border-style:var(--navbar-root-border-style); + border-color:var(--navbar-root-border-color); + border-radius:var(--navbar-root-border-radius); + background:var(--navbar-root-background); + color:var(--navbar-root-color); + -webkit-text-decoration:var(--navbar-root-text-decoration); + text-decoration:var(--navbar-root-text-decoration); + -webkit-text-decoration-color:var(--navbar-root-text-decoration-color); + text-decoration-color:var(--navbar-root-text-decoration-color) +} +.app-nav>ul>li>a:hover,.app-nav>ul>li>span:hover{ + background:var(--navbar-root-background--hover, var(--navbar-root-background)); + border-style:var(--navbar-root-border-style--hover, var(--navbar-root-border-style)); + border-color:var(--navbar-root-border-color--hover, var(--navbar-root-border-color)); + color:var(--navbar-root-color--hover, var(--navbar-root-color)); + -webkit-text-decoration:var(--navbar-root-text-decoration--hover, var(--navbar-root-text-decoration)); + text-decoration:var(--navbar-root-text-decoration--hover, var(--navbar-root-text-decoration)); + -webkit-text-decoration-color:var(--navbar-root-text-decoration-color--hover, var(--navbar-root-text-decoration-color)); + text-decoration-color:var(--navbar-root-text-decoration-color--hover, var(--navbar-root-text-decoration-color)) +} +.app-nav>ul>li>a:not(:last-child),.app-nav>ul>li>span:not(:last-child){ + padding:var(--navbar-menu-root-padding, var(--navbar-root-padding)); + background:var(--navbar-menu-root-background, var(--navbar-root-background)) +} +.app-nav>ul>li>a:not(:last-child):hover,.app-nav>ul>li>span:not(:last-child):hover{ + background:var(--navbar-menu-root-background--hover, var(--navbar-menu-root-background, var(--navbar-root-background--hover, var(--navbar-root-background)))) +} +.app-nav>ul>li>a.active{ + background:var(--navbar-root-background--active, var(--navbar-root-background)); + border-style:var(--navbar-root-border-style--active, var(--navbar-root-border-style)); + border-color:var(--navbar-root-border-color--active, var(--navbar-root-border-color)); + color:var(--navbar-root-color--active, var(--navbar-root-color)); + -webkit-text-decoration:var(--navbar-root-text-decoration--active, var(--navbar-root-text-decoration)); + text-decoration:var(--navbar-root-text-decoration--active, var(--navbar-root-text-decoration)); + -webkit-text-decoration-color:var(--navbar-root-text-decoration-color--active, var(--navbar-root-text-decoration-color)); + text-decoration-color:var(--navbar-root-text-decoration-color--active, var(--navbar-root-text-decoration-color)) +} +.app-nav>ul>li>a.active:not(:last-child):hover{ + background:var(--navbar-menu-root-background--active, var(--navbar-menu-root-background, var(--navbar-root-background--active, var(--navbar-root-background)))) +} +.app-nav>ul>li ul{ + visibility:hidden; + position:absolute; + top:100%; + right:50%; + overflow-y:auto; + box-sizing:border-box; + max-height:50vh; + padding:var(--navbar-menu-padding); + border-width:var(--navbar-menu-border-width, 0); + border-style:solid; + border-color:var(--navbar-menu-border-color); + border-radius:var(--navbar-menu-border-radius); + background:var(--navbar-menu-background); + box-shadow:var(--navbar-menu-box-shadow); + text-align:left; + white-space:nowrap; + opacity:0; + transform:translate(50%, -0.35em); + transition:var(--navbar-menu-transition) +} +.app-nav>ul>li ul li{ + white-space:nowrap +} +.app-nav>ul>li ul a{ + margin:var(--navbar-menu-link-margin); + padding:var(--navbar-menu-link-padding); + border-width:var(--navbar-menu-link-border-width, 0); + border-style:var(--navbar-menu-link-border-style); + border-color:var(--navbar-menu-link-border-color); + border-radius:var(--navbar-menu-link-border-radius); + background:var(--navbar-menu-link-background); + color:var(--navbar-menu-link-color); + -webkit-text-decoration:var(--navbar-menu-link-text-decoration); + text-decoration:var(--navbar-menu-link-text-decoration); + -webkit-text-decoration-color:var(--navbar-menu-link-text-decoration-color); + text-decoration-color:var(--navbar-menu-link-text-decoration-color) +} +.app-nav>ul>li ul a:hover{ + background:var(--navbar-menu-link-background--hover, var(--navbar-menu-link-background)); + border-style:var(--navbar-menu-link-border-style--hover, var(--navbar-menu-link-border-style)); + border-color:var(--navbar-menu-link-border-color--hover, var(--navbar-menu-link-border-color)); + color:var(--navbar-menu-link-color--hover, var(--navbar-menu-link-color)); + -webkit-text-decoration:var(--navbar-menu-link-text-decoration--hover, var(--navbar-menu-link-text-decoration)); + text-decoration:var(--navbar-menu-link-text-decoration--hover, var(--navbar-menu-link-text-decoration)); + -webkit-text-decoration-color:var(--navbar-menu-link-text-decoration-color--hover, var(--navbar-menu-link-text-decoration-color)); + text-decoration-color:var(--navbar-menu-link-text-decoration-color--hover, var(--navbar-menu-link-text-decoration-color)) +} +.app-nav>ul>li ul a.active{ + background:var(--navbar-menu-link-background--active, var(--navbar-menu-link-background)); + border-style:var(--navbar-menu-link-border-style--active, var(--navbar-menu-link-border-style)); + border-color:var(--navbar-menu-link-border-color--active, var(--navbar-menu-link-border-color)); + color:var(--navbar-menu-link-color--active, var(--navbar-menu-link-color)); + -webkit-text-decoration:var(--navbar-menu-link-text-decoration--active, var(--navbar-menu-link-text-decoration)); + text-decoration:var(--navbar-menu-link-text-decoration--active, var(--navbar-menu-link-text-decoration)); + -webkit-text-decoration-color:var(--navbar-menu-link-text-decoration-color--active, var(--navbar-menu-link-text-decoration-color)); + text-decoration-color:var(--navbar-menu-link-text-decoration-color--active, var(--navbar-menu-link-text-decoration-color)) +} +.app-nav>ul>li:hover ul,.app-nav>ul>li:focus ul,.app-nav>ul>li.focus-within ul{ + visibility:visible; + opacity:1; + transform:translate(50%, 0) +} +@media(min-width: 48em){ + nav.app-nav{ + margin-left:var(--sidebar-width) + } +} +.sidebar,.sidebar-toggle,.sidebar+.content{ + transition:all var(--sidebar-transition-duration) ease-out +} +@media(min-width: 48em){ + .sidebar+.content{ + margin-left:var(--sidebar-width) + } +} +.sidebar{ + display:flex; + flex-direction:column; + position:fixed; + z-index:10; + top:0; + right:100%; + overflow-x:hidden; + overflow-y:auto; + height:100vh; + width:var(--sidebar-width); + padding:var(--sidebar-padding); + border-width:var(--sidebar-border-width); + border-style:solid; + border-color:var(--sidebar-border-color); + background:var(--sidebar-background) +} +.sidebar>h1{ + margin:0; + margin:var(--sidebar-name-margin); + padding:var(--sidebar-name-padding); + background:var(--sidebar-name-background); + color:var(--sidebar-name-color); + font-family:var(--sidebar-name-font-family); + font-size:var(--sidebar-name-font-size); + font-weight:var(--sidebar-name-font-weight); + text-align:var(--sidebar-name-text-align) +} +.sidebar>h1 img{ + max-width:100% +} +.sidebar>h1 .app-name-link{ + color:var(--sidebar-name-color) +} +body:not([data-platform^=Mac]) .sidebar::-webkit-scrollbar{ + width:5px +} +body:not([data-platform^=Mac]) .sidebar::-webkit-scrollbar-thumb{ + border-radius:50vw +} +@media(min-width: 48em){ + .sidebar{ + position:absolute; + transform:translateX(var(--sidebar-width)) + } +} +@media print{ + .sidebar{ + display:none + } +} +.sidebar-nav,.sidebar nav{ + order:1; + margin:var(--sidebar-nav-margin); + padding:var(--sidebar-nav-padding); + background:var(--sidebar-nav-background) +} +.sidebar-nav ul,.sidebar nav ul{ + margin:0; + padding:0; + list-style:none +} +.sidebar-nav ul ul,.sidebar nav ul ul{ + margin-left:var(--sidebar-nav-indent) +} +.sidebar-nav a,.sidebar nav a{ + display:block; + overflow:hidden; + margin:var(--sidebar-nav-link-margin); + padding:var(--sidebar-nav-link-padding); + border-width:var(--sidebar-nav-link-border-width, 0); + border-style:var(--sidebar-nav-link-border-style); + border-color:var(--sidebar-nav-link-border-color); + border-radius:var(--sidebar-nav-link-border-radius); + background:var(--sidebar-nav-link-background); + color:var(--sidebar-nav-link-color); + font-weight:var(--sidebar-nav-link-font-weight); + white-space:nowrap; + -webkit-text-decoration:var(--sidebar-nav-link-text-decoration); + text-decoration:var(--sidebar-nav-link-text-decoration); + -webkit-text-decoration-color:var(--sidebar-nav-link-text-decoration-color); + text-decoration-color:var(--sidebar-nav-link-text-decoration-color); + text-overflow:ellipsis; + transition:var(--sidebar-nav-link-transition) +} +.sidebar-nav a img,.sidebar nav a img{ + margin-top:-0.25em; + vertical-align:middle +} +.sidebar-nav a img:first-child,.sidebar nav a img:first-child{ + margin-right:.5em +} +.sidebar-nav a:hover,.sidebar nav a:hover{ + border-width:var(--sidebar-nav-link-border-width--hover, var(--sidebar-nav-link-border-width, 0)); + border-style:var(--sidebar-nav-link-border-style--hover, var(--sidebar-nav-link-border-style)); + border-color:var(--sidebar-nav-link-border-color--hover, var(--sidebar-nav-link-border-color)); + background:var(--sidebar-nav-link-background--hover, var(--sidebar-nav-link-background)); + color:var(--sidebar-nav-link-color--hover, var(--sidebar-nav-link-color)); + font-weight:var(--sidebar-nav-link-font-weight--hover, var(--sidebar-nav-link-font-weight)); + -webkit-text-decoration:var(--sidebar-nav-link-text-decoration--hover, var(--sidebar-nav-link-text-decoration)); + text-decoration:var(--sidebar-nav-link-text-decoration--hover, var(--sidebar-nav-link-text-decoration)); + -webkit-text-decoration-color:var(--sidebar-nav-link-text-decoration-color); + text-decoration-color:var(--sidebar-nav-link-text-decoration-color) +} +.sidebar-nav ul>li>span,.sidebar-nav ul>li>strong,.sidebar nav ul>li>span,.sidebar nav ul>li>strong{ + display:block; + margin:var(--sidebar-nav-strong-margin); + padding:var(--sidebar-nav-strong-padding); + border-width:var(--sidebar-nav-strong-border-width, 0); + border-style:solid; + border-color:var(--sidebar-nav-strong-border-color); + color:var(--sidebar-nav-strong-color); + font-size:var(--sidebar-nav-strong-font-size); + font-weight:var(--sidebar-nav-strong-font-weight); + text-transform:var(--sidebar-nav-strong-text-transform) +} +.sidebar-nav ul>li>span+ul,.sidebar-nav ul>li>strong+ul,.sidebar nav ul>li>span+ul,.sidebar nav ul>li>strong+ul{ + margin-left:0 +} +.sidebar-nav ul>li:first-child>span,.sidebar-nav ul>li:first-child>strong,.sidebar nav ul>li:first-child>span,.sidebar nav ul>li:first-child>strong{ + margin-top:0 +} +.sidebar-nav::-webkit-scrollbar,.sidebar nav::-webkit-scrollbar{ + width:0 +} +@supports(width: env(safe-area-inset)){ + @media only screen and (orientation: landscape){ + .sidebar-nav,.sidebar nav{ + margin-left:calc(env(safe-area-inset-left)/2) + } + } +} +.sidebar-nav li>a:before,.sidebar-nav li>strong:before{ + display:inline-block +} +.sidebar-nav li>a{ + background-repeat:var(--sidebar-nav-pagelink-background-repeat); + background-size:var(--sidebar-nav-pagelink-background-size) +} +.sidebar-nav li>a[href^="/"]:not([href*="?id="]),.sidebar-nav li>a[href^="#/"]:not([href*="?id="]){ + transition:var(--sidebar-nav-pagelink-transition) +} +.sidebar-nav li>a[href^="/"]:not([href*="?id="]),.sidebar-nav li>a[href^="/"]:not([href*="?id="])~ul a,.sidebar-nav li>a[href^="#/"]:not([href*="?id="]),.sidebar-nav li>a[href^="#/"]:not([href*="?id="])~ul a{ + padding:var(--sidebar-nav-pagelink-padding, var(--sidebar-nav-link-padding)) +} +.sidebar-nav li>a[href^="/"]:not([href*="?id="]):only-child,.sidebar-nav li>a[href^="#/"]:not([href*="?id="]):only-child{ + background:var(--sidebar-nav-pagelink-background) +} +.sidebar-nav li>a[href^="/"]:not([href*="?id="]):not(:only-child),.sidebar-nav li>a[href^="#/"]:not([href*="?id="]):not(:only-child){ + background:var(--sidebar-nav-pagelink-background--loaded, var(--sidebar-nav-pagelink-background)) +} +.sidebar-nav li.active>a,.sidebar-nav li.collapse>a{ + border-width:var(--sidebar-nav-link-border-width--active, var(--sidebar-nav-link-border-width)); + border-style:var(--sidebar-nav-link-border-style--active, var(--sidebar-nav-link-border-style)); + border-color:var(--sidebar-nav-link-border-color--active, var(--sidebar-nav-link-border-color)); + background:var(--sidebar-nav-link-background--active, var(--sidebar-nav-link-background)); + color:var(--sidebar-nav-link-color--active, var(--sidebar-nav-link-color)); + font-weight:var(--sidebar-nav-link-font-weight--active, var(--sidebar-nav-link-font-weight)); + -webkit-text-decoration:var(--sidebar-nav-link-text-decoration--active, var(--sidebar-nav-link-text-decoration)); + text-decoration:var(--sidebar-nav-link-text-decoration--active, var(--sidebar-nav-link-text-decoration)); + -webkit-text-decoration-color:var(--sidebar-nav-link-text-decoration-color); + text-decoration-color:var(--sidebar-nav-link-text-decoration-color) +} +.sidebar-nav li.active>a[href^="/"]:not([href*="?id="]):not(:only-child),.sidebar-nav li.active>a[href^="#/"]:not([href*="?id="]):not(:only-child){ + background:var(--sidebar-nav-pagelink-background--active, var(--sidebar-nav-pagelink-background--loaded, var(--sidebar-nav-pagelink-background))) +} +.sidebar-nav li.collapse>a[href^="/"]:not([href*="?id="]):not(:only-child),.sidebar-nav li.collapse>a[href^="#/"]:not([href*="?id="]):not(:only-child){ + background:var(--sidebar-nav-pagelink-background--collapse, var(--sidebar-nav-pagelink-background--loaded, var(--sidebar-nav-pagelink-background))) +} +.sidebar-nav li.collapse .app-sub-sidebar{ + display:none +} +.sidebar-nav>ul>li>a:before{ + content:var(--sidebar-nav-link-before-content-l1, var(--sidebar-nav-link-before-content)); + margin:var(--sidebar-nav-link-before-margin-l1, var(--sidebar-nav-link-before-margin)); + color:var(--sidebar-nav-link-before-color-l1, var(--sidebar-nav-link-before-color)) +} +.sidebar-nav>ul>li.active>a:before{ + content:var(--sidebar-nav-link-before-content-l1--active, var(--sidebar-nav-link-before-content--active, var(--sidebar-nav-link-before-content-l1, var(--sidebar-nav-link-before-content)))); + color:var(--sidebar-nav-link-before-color-l1--active, var(--sidebar-nav-link-before-color--active, var(--sidebar-nav-link-before-color-l1, var(--sidebar-nav-link-before-color)))) +} +.sidebar-nav>ul>li>ul>li>a:before{ + content:var(--sidebar-nav-link-before-content-l2, var(--sidebar-nav-link-before-content)); + margin:var(--sidebar-nav-link-before-margin-l2, var(--sidebar-nav-link-before-margin)); + color:var(--sidebar-nav-link-before-color-l2, var(--sidebar-nav-link-before-color)) +} +.sidebar-nav>ul>li>ul>li.active>a:before{ + content:var(--sidebar-nav-link-before-content-l2--active, var(--sidebar-nav-link-before-content--active, var(--sidebar-nav-link-before-content-l2, var(--sidebar-nav-link-before-content)))); + color:var(--sidebar-nav-link-before-color-l2--active, var(--sidebar-nav-link-before-color--active, var(--sidebar-nav-link-before-color-l2, var(--sidebar-nav-link-before-color)))) +} +.sidebar-nav>ul>li>ul>li>ul>li>a:before{ + content:var(--sidebar-nav-link-before-content-l3, var(--sidebar-nav-link-before-content)); + margin:var(--sidebar-nav-link-before-margin-l3, var(--sidebar-nav-link-before-margin)); + color:var(--sidebar-nav-link-before-color-l3, var(--sidebar-nav-link-before-color)) +} +.sidebar-nav>ul>li>ul>li>ul>li.active>a:before{ + content:var(--sidebar-nav-link-before-content-l3--active, var(--sidebar-nav-link-before-content--active, var(--sidebar-nav-link-before-content-l3, var(--sidebar-nav-link-before-content)))); + color:var(--sidebar-nav-link-before-color-l3--active, var(--sidebar-nav-link-before-color--active, var(--sidebar-nav-link-before-color-l3, var(--sidebar-nav-link-before-color)))) +} +.sidebar-nav>ul>li>ul>li>ul>li>ul>li>a:before{ + content:var(--sidebar-nav-link-before-content-l4, var(--sidebar-nav-link-before-content)); + margin:var(--sidebar-nav-link-before-margin-l4, var(--sidebar-nav-link-before-margin)); + color:var(--sidebar-nav-link-before-color-l4, var(--sidebar-nav-link-before-color)) +} +.sidebar-nav>ul>li>ul>li>ul>li>ul>li.active>a:before{ + content:var(--sidebar-nav-link-before-content-l4--active, var(--sidebar-nav-link-before-content--active, var(--sidebar-nav-link-before-content-l4, var(--sidebar-nav-link-before-content)))); + color:var(--sidebar-nav-link-before-color-l4--active, var(--sidebar-nav-link-before-color--active, var(--sidebar-nav-link-before-color-l4, var(--sidebar-nav-link-before-color)))) +} +.sidebar-nav>:last-child{ + margin-bottom:2rem +} +.sidebar-toggle,.sidebar-toggle-button{ + width:var(--sidebar-toggle-width); + outline:none +} +.sidebar-toggle{ + position:fixed; + z-index:11; + top:0; + bottom:0; + left:0; + max-width:40px; + margin:0; + padding:0; + border:0; + background:rgba(0,0,0,0); + -webkit-appearance:none; + -moz-appearance:none; + appearance:none; + cursor:pointer +} +.sidebar-toggle .sidebar-toggle-button{ + position:absolute; + top:var(--sidebar-toggle-offset-top); + left:var(--sidebar-toggle-offset-left); + height:var(--sidebar-toggle-height); + border-radius:var(--sidebar-toggle-border-radius); + border-width:var(--sidebar-toggle-border-width); + border-style:var(--sidebar-toggle-border-style); + border-color:var(--sidebar-toggle-border-color); + background:var(--sidebar-toggle-background, transparent); + color:var(--sidebar-toggle-icon-color) +} +.sidebar-toggle span{ + position:absolute; + top:calc(50% - var(--sidebar-toggle-icon-stroke-width)/2); + left:calc(50% - var(--sidebar-toggle-icon-width)/2); + height:var(--sidebar-toggle-icon-stroke-width); + width:var(--sidebar-toggle-icon-width); + background-color:currentColor +} +.sidebar-toggle span:nth-child(1){ + margin-top:calc(0px - var(--sidebar-toggle-icon-height)/2) +} +.sidebar-toggle span:nth-child(3){ + margin-top:calc(var(--sidebar-toggle-icon-height)/2) +} +@media(min-width: 48em){ + .sidebar-toggle{ + position:absolute; + overflow:visible; + top:var(--sidebar-toggle-offset-top); + bottom:auto; + left:0; + height:var(--sidebar-toggle-height); + transform:translateX(var(--sidebar-width)) + } + .sidebar-toggle .sidebar-toggle-button{ + top:0 + } +} +@media print{ + .sidebar-toggle{ + display:none + } +} +@media(max-width: 47.99em){ + body.close .sidebar,body.close .sidebar-toggle,body.close .sidebar+.content{ + transform:translateX(var(--sidebar-width)) + } +} +@media(min-width: 48em){ + body.close .sidebar+.content{ + transform:translateX(0) + } +} +@media(max-width: 47.99em){ + body.close nav.app-nav,body.close .github-corner{ + display:none + } +} +@media(min-width: 48em){ + body.close .sidebar,body.close .sidebar-toggle{ + transform:translateX(0) + } +} +@media(min-width: 48em){ + body.close nav.app-nav{ + margin-left:0 + } +} +@media(max-width: 47.99em){ + body.close .sidebar-toggle{ + width:100%; + max-width:none + } + body.close .sidebar-toggle span{ + margin-top:0 + } + body.close .sidebar-toggle span:nth-child(1){ + transform:rotate(45deg) + } + body.close .sidebar-toggle span:nth-child(2){ + display:none + } + body.close .sidebar-toggle span:nth-child(3){ + transform:rotate(-45deg) + } +} +@media(min-width: 48em){ + body.close .sidebar+.content{ + margin-left:0 + } +} +@media(min-width: 48em){ + body.sticky .sidebar,body.sticky .sidebar-toggle{ + position:fixed + } +} +body .docsify-copy-code-button,body .docsify-copy-code-button:after{ + border-radius:var(--border-radius-m, 0); + border-top-left-radius:0; + border-bottom-right-radius:0; + background:var(--copycode-background); + color:var(--copycode-color) +} +body .docsify-copy-code-button span{ + border-radius:var(--border-radius-s, 0) +} +body .docsify-pagination-container{ + border-top:var(--pagination-border-top); + color:var(--pagination-color) +} +body .pagination-item-label{ + font-size:var(--pagination-label-font-size) +} +body .pagination-item-label svg{ + color:var(--pagination-label-color); + height:var(--pagination-chevron-height); + stroke:var(--pagination-chevron-stroke); + stroke-linecap:var(--pagination-chevron-stroke-linecap); + stroke-linejoin:var(--pagination-chevron-stroke-linecap); + stroke-width:var(--pagination-chevron-stroke-width) +} +body .pagination-item-title{ + color:var(--pagination-title-color); + font-size:var(--pagination-title-font-size) +} +body .app-name.hide{ + display:block +} +body .sidebar{ + padding:var(--sidebar-padding) +} +.sidebar .search input{ + padding:0; + line-height:1; + font-size:inherit +} +.sidebar .search .clear-button svg{ + transform:scale(1) +} +.sidebar .search{ + order:var(--search-flex-order); + margin:var(--search-margin); + padding:var(--search-padding); + background:var(--search-background) +} +.sidebar .search a{ + color:inherit +} +.sidebar .search h2{ + margin:var(--search-result-heading-margin); + font-size:var(--search-result-heading-font-size); + font-weight:var(--search-result-heading-font-weight); + color:var(--search-result-heading-color) +} +.sidebar .search .input-wrap{ + align-items:stretch; + margin:var(--search-input-margin); + background-color:var(--search-input-background-color); + border-width:var(--search-input-border-width, 0); + border-style:solid; + border-color:var(--search-input-border-color); + border-radius:var(--search-input-border-radius) +} +.sidebar .search input[type=search]{ + min-width:0; + padding:var(--search-input-padding); + border:none; + background-color:rgba(0,0,0,0); + background-image:var(--search-input-background-image); + background-position:var(--search-input-background-position); + background-repeat:var(--search-input-background-repeat); + background-size:var(--search-input-background-size); + font-size:var(--search-input-font-size); + color:var(--search-input-color); + transition:var(--search-input-transition) +} +.sidebar .search input[type=search]::-ms-clear{ + display:none +} +.sidebar .search input[type=search]::-moz-placeholder{ + color:var(--search-input-placeholder-color, #808080) +} +.sidebar .search input[type=search]::placeholder{ + color:var(--search-input-placeholder-color, #808080) +} +.sidebar .search input[type=search]::-webkit-input-placeholder{ + line-height:normal +} +.sidebar .search input[type=search]:focus{ + background-color:var(--search-input-background-color--focus, var(--search-input-background-color)); + background-image:var(--search-input-background-image--focus, var(--search-input-background-image)); + background-position:var(--search-input-background-position--focus, var(--search-input-background-position)); + background-size:var(--search-input-background-size--focus, var(--search-input-background-size)) +} +@supports(width: env(safe-area-inset)){ + @media only screen and (orientation: landscape){ + .sidebar .search input[type=search]{ + margin-left:calc(env(safe-area-inset-left)/2) + } + } +} +.sidebar .search p{ + font-size:inherit; + overflow:hidden; + text-overflow:ellipsis; + -webkit-box-orient:vertical; + -webkit-line-clamp:2; + line-clamp:2 +} +.sidebar .search p:empty{ + text-align:center +} +.sidebar .search .clear-button{ + width:auto; + margin:0; + padding:0 10px; + border:none; + line-height:1; + background:rgba(0,0,0,0); + cursor:pointer +} +.sidebar .search .clear-button svg circle{ + fill:var(--search-clear-icon-color1, #808080) +} +.sidebar .search .clear-button svg path{ + stroke:var(--search-clear-icon-color2, #fff) +} +.sidebar .search.show~*:not(h1){ + display:none +} +.sidebar .search .results-panel{ + display:none; + color:var(--search-result-item-color); + font-size:var(--search-result-item-font-size); + font-weight:var(--search-result-item-font-weight) +} +.sidebar .search .results-panel.show{ + display:block +} +.sidebar .search .matching-post{ + border:none; + margin:var(--search-result-item-margin); + padding:var(--search-result-item-padding) +} +.sidebar .search .matching-post,.sidebar .search .matching-post:last-child{ + border-width:var(--search-result-item-border-width, 0) !important; + border-style:var(--search-result-item-border-style); + border-color:var(--search-result-item-border-color) +} +.sidebar .search .matching-post p{ + margin:0 +} +.sidebar .search .search-keyword{ + margin:var(--search-result-keyword-margin); + padding:var(--search-result-keyword-padding); + border-radius:var(--search-result-keyword-border-radius); + background-color:var(--search-result-keyword-background); + color:var(--search-result-keyword-color, currentColor); + font-style:normal; + font-weight:var(--search-result-keyword-font-weight) +} +.medium-zoom-overlay,.medium-zoom-image--open,.medium-zoom-image--opened{ + z-index:2147483646 !important +} +.medium-zoom-overlay{ + background:var(--zoomimage-overlay-background) !important +} diff --git a/lib/averages/Ema.cs b/lib/averages/Ema.cs index 9d53fa4..6e7c7d9 100644 --- a/lib/averages/Ema.cs +++ b/lib/averages/Ema.cs @@ -2,10 +2,11 @@ namespace QuanTAlib; /// /// EMA: Exponential Moving Average -/// EMA needs very short history buffer and calculates the EMA value using just the -/// previous EMA value. The weight of the new datapoint (alpha) is alpha = 2 / (period + 1) /// /// +/// EMA needs very short history buffer and calculates the EMA value using just the +/// previous EMA value. The weight of the new datapoint (alpha) is alpha = 2 / (period + 1) +/// /// Key characteristics: /// - Uses no buffer, relying only on the previous EMA value. /// - The weight of new data points is calculated as alpha = 2 / (period + 1). @@ -19,19 +20,52 @@ namespace QuanTAlib; /// - https://www.investopedia.com/ask/answers/122314/what-exponential-moving-average-ema-formula-and-how-ema-calculated.asp /// - https://blog.fugue88.ws/archives/2017-01/The-correct-way-to-start-an-Exponential-Moving-Average-EMA /// - public class Ema : AbstractBase { // inherited _index // inherited _value + + /// + /// The period for the EMA calculation. + /// private readonly int _period; + + /// + /// Circular buffer for SMA calculation. + /// private CircularBuffer _sma; + + /// + /// The last calculated EMA value. + /// private double _lastEma, _p_lastEma; + + /// + /// Compensator for early EMA values. + /// private double _e, _p_e; + + /// + /// The smoothing factor for EMA calculation. + /// private readonly double _k; + + /// + /// Flags to track initialization status. + /// private bool _isInit, _p_isInit; + + /// + /// Flag to determine whether to use SMA for initial values. + /// private readonly bool _useSma; + /// + /// Initializes a new instance of the Ema class with a specified period. + /// + /// The period for EMA calculation. + /// Whether to use SMA for initial values. Default is true. + /// Thrown when period is less than 1. public Ema(int period, bool useSma = true) { if (period < 1) @@ -47,6 +81,10 @@ public Ema(int period, bool useSma = true) Init(); } + /// + /// Initializes a new instance of the Ema class with a specified alpha value. + /// + /// The smoothing factor for EMA calculation. public Ema(double alpha) { _k = alpha; @@ -57,13 +95,21 @@ public Ema(double alpha) Init(); } + /// + /// Initializes a new instance of the Ema class with a specified source and period. + /// + /// The source object for event subscription. + /// The period for EMA calculation. + /// Whether to use SMA for initial values. Default is true. public Ema(object source, int period, bool useSma = true) : this(period, useSma) { var pubEvent = source.GetType().GetEvent("Pub"); pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); } - //inhereted public void Sub(object source, in ValueEventArgs args) + /// + /// Initializes the Ema instance. + /// public override void Init() { base.Init(); @@ -74,6 +120,10 @@ public override void Init() _sma = new(_period); } + /// + /// Manages the state of the Ema instance. + /// + /// Indicates whether the input is new. protected override void ManageState(bool isNew) { if (isNew) @@ -92,8 +142,9 @@ protected override void ManageState(bool isNew) } /// - /// Core EMA calculation + /// Performs the EMA calculation. /// + /// The calculated EMA value. protected override double Calculation() { double result, _ema; @@ -118,7 +169,7 @@ protected override double Calculation() _ema = _k * (Input.Value - _lastEma) + _lastEma; // _useSma decides if we use compensator or not - result = (_useSma || _e == 0) ? _ema : _ema / (1 - _e); + result = (_useSma || _e <= double.Epsilon) ? _ema : _ema / (1 - _e); } _lastEma = _ema; IsHot = _index >= WarmupPeriod; diff --git a/lib/averages/Jma.cs b/lib/averages/Jma.cs index 8a71cd0..142a47d 100644 --- a/lib/averages/Jma.cs +++ b/lib/averages/Jma.cs @@ -1,68 +1,91 @@ +/// +/// Represents a Jurik Moving Average, based on known and reverse-engineered insights +/// + namespace QuanTAlib; -//TODO fails consistency test + public class Jma : AbstractBase { - public readonly int Period; + private readonly int _period; private readonly double _phase; - private readonly int _vshort, _vlong; - private readonly CircularBuffer _values; - private readonly CircularBuffer _voltyShort; private readonly CircularBuffer _vsumBuff; private readonly CircularBuffer _avoltyBuff; - private double _beta, _len1, _pow1; - private double _upperBand, _lowerBand, _prevMa1, _prevDet0, _prevDet1, _prevJma; - private double _p_UpperBand, _p_LowerBand, _p_prevMa1, _p_prevDet0, _p_prevDet1, _p_prevJma; - - public Jma(int period, double phase = 0, int vshort = 10) + private double _len1; + private double _pow1; + private readonly double _beta; + private double _upperBand, _lowerBand, _p_upperBand, _p_lowerBand; + private double _prevMa1, _prevDet0, _prevDet1, _prevJma, _p_prevMa1, _p_prevDet0, _p_prevDet1, _p_prevJma; + private double _vSum, _p_vSum; + + + public double UpperBand { get; set; } + public double LowerBand { get; set; } + public double Volty { get; set; } + + /// + /// Initializes a new instance of the Jma class with the specified parameters. + /// + /// The period over which to calculate the Jvolty. + /// The phase parameter for the JMA-style calculation. + /// + /// Thrown when period is less than 1. + /// + public Jma(int period, int phase = 0) { if (period < 1) { throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1."); } - Period = period; - _vshort = vshort; - _vlong = 65; + _period = period; _phase = Math.Clamp((phase * 0.01) + 1.5, 0.5, 2.5); - _values = new CircularBuffer(period); - _voltyShort = new CircularBuffer(vshort); - _vsumBuff = new CircularBuffer(_vlong); - _avoltyBuff = new CircularBuffer(2); + _vsumBuff = new CircularBuffer(10); + _avoltyBuff = new CircularBuffer(65); + _beta = 0.45 * (period - 1) / (0.45 * (period - 1) + 2); - Name = "JMA"; WarmupPeriod = period * 2; - Init(); + Name = $"JMA({period})"; } - public Jma(object source, int period, double phase = 0, int vshort = 10) : this(period, phase, vshort) + /// + /// Initializes a new instance of the Jvolty class with the specified source and parameters. + /// + /// The source object to subscribe to for value updates. + /// The period over which to calculate the Jvolty. + /// The phase parameter for the JMA-style calculation. + public Jma(object source, int period, int phase = 0) : this(period, phase) { var pubEvent = source.GetType().GetEvent("Pub"); pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); } + /// + /// Initializes the Jma instance by setting up the initial state. + /// public override void Init() { - _upperBand = _lowerBand = _prevMa1 = _prevDet0 = _prevDet1 = _prevJma = 0.0; - _p_UpperBand = _p_LowerBand = _p_prevMa1 = _p_prevDet0 = _p_prevDet1 = _p_prevJma = 0.0; - _beta = 0.45 * (Period - 1) / (0.45 * (Period - 1) + 2); - _len1 = Math.Max((Math.Log(Math.Sqrt(Period - 1)) / Math.Log(2.0)) + 2.0, 0); + base.Init(); + _upperBand = _lowerBand = 0.0; + _p_upperBand = _p_lowerBand = 0.0; + _len1 = Math.Max((Math.Log(Math.Sqrt(_period - 1)) / Math.Log(2.0)) + 2.0, 0); _pow1 = Math.Max(_len1 - 2.0, 0.5); _avoltyBuff.Clear(); - _avoltyBuff.Add(0, true); - _avoltyBuff.Add(0, true); - base.Init(); + _vsumBuff.Clear(); } + /// + /// Manages the state of the Jma instance based on whether a new value is being processed. + /// + /// Indicates whether the current input is a new value. protected override void ManageState(bool isNew) { if (isNew) { - _lastValidValue = Input.Value; _index++; - // Save current state - _p_UpperBand = _upperBand; - _p_LowerBand = _lowerBand; + _p_upperBand = _upperBand; + _p_lowerBand = _lowerBand; + _p_vSum = _vSum; _p_prevMa1 = _prevMa1; _p_prevDet0 = _prevDet0; _p_prevDet1 = _prevDet1; @@ -70,67 +93,68 @@ protected override void ManageState(bool isNew) } else { - // Restore previous state - _upperBand = _p_UpperBand; - _lowerBand = _p_LowerBand; + _upperBand = _p_upperBand; + _lowerBand = _p_lowerBand; + _vSum = _p_vSum; _prevMa1 = _p_prevMa1; _prevDet0 = _p_prevDet0; _prevDet1 = _p_prevDet1; _prevJma = _p_prevJma; - } } + + /// + /// Performs the Jma calculation for the current value. + /// + /// + /// The calculated Jma value for the current input. + /// protected override double Calculation() { ManageState(Input.IsNew); - _values.Add(Input.Value, Input.IsNew); - + double price = Input.Value; if (_index == 1) { - _prevMa1 = _prevJma = Input.Value; - return Input.Value; + _upperBand = _lowerBand = price; } - double hprice = _values.Max(); - double lprice = _values.Min(); - - double del1 = hprice - _upperBand; - double del2 = lprice - _lowerBand; + double del1 = price - _upperBand; + double del2 = price - _lowerBand; double volty = Math.Max(Math.Abs(del1), Math.Abs(del2)); - _voltyShort.Add(volty, Input.IsNew); - double vsum = _vsumBuff.Newest() + 0.1 * (volty - _voltyShort.Oldest()); - _vsumBuff.Add(vsum, Input.IsNew); + _vsumBuff.Add(volty, Input.IsNew); + _vSum += (_vsumBuff[^1] - _vsumBuff[0]) / 10; + _avoltyBuff.Add(_vSum, Input.IsNew); + double avgvolty = _avoltyBuff.Average(); - double prevAvolty = _avoltyBuff.Newest(); - double avolty = prevAvolty + 2.0 / (Math.Max(4.0 * Period, 30) + 1.0) * (vsum - prevAvolty); - _avoltyBuff.Add(avolty, Input.IsNew); + double rvolty = (avgvolty > 0) ? volty / avgvolty : 1; + rvolty = Math.Min(Math.Max(rvolty, 1.0), Math.Pow(_len1, 1.0 / _pow1)); - double dVolty = (avolty > 0) ? volty / avolty : 0; - dVolty = Math.Min(Math.Max(dVolty, 1.0), Math.Pow(_len1, 1.0 / _pow1)); + double pow2 = Math.Pow(rvolty, _pow1); + double Kv = Math.Pow(_beta, Math.Sqrt(pow2)); - double pow2 = Math.Pow(dVolty, _pow1); - double len2 = Math.Sqrt(0.5 * (Period - 1)) * _len1; - double _Kv = Math.Pow(len2 / (len2 + 1), Math.Sqrt(pow2)); - - _upperBand = (del1 > 0) ? hprice : hprice - (_Kv * del1); - _lowerBand = (del2 < 0) ? lprice : lprice - (_Kv * del2); + _upperBand = (del1 >= 0) ? price : price - (Kv * del1); + _lowerBand = (del2 <= 0) ? price : price - (Kv * del2); double alpha = Math.Pow(_beta, pow2); double ma1 = (1 - alpha) * Input.Value + alpha * _prevMa1; _prevMa1 = ma1; - double det0 = (1 - _beta) * (Input.Value - ma1) + _beta * _prevDet0; + double det0 = (price - ma1) * (1 - _beta) + _beta * _prevDet0; _prevDet0 = det0; - double ma2 = ma1 + (_phase + 1) * det0; + double ma2 = ma1 + _phase * det0; - double det1 = ((1 - alpha) * (1 - alpha) * (ma2 - _prevJma)) + (alpha * alpha * _prevDet1); + double det1 = ((ma2 - _prevJma) * (1 - alpha) * (1 - alpha) ) + (alpha * alpha * _prevDet1); _prevDet1 = det1; double jma = _prevJma + det1; _prevJma = jma; + UpperBand = _upperBand; + LowerBand = _lowerBand; + Volty = volty; + IsHot = _index >= WarmupPeriod; return jma; } -} \ No newline at end of file +} diff --git a/lib/volatility/Jvolty.cs b/lib/volatility/Jvolty.cs index dba3208..23f6ae9 100644 --- a/lib/volatility/Jvolty.cs +++ b/lib/volatility/Jvolty.cs @@ -7,17 +7,25 @@ namespace QuanTAlib; public class Jvolty : AbstractBase { private readonly int _period; - private readonly CircularBuffer _values; - private readonly CircularBuffer _voltyShort; + private readonly double _phase; private readonly CircularBuffer _vsumBuff; private readonly CircularBuffer _avoltyBuff; private double _len1; private double _pow1; - private double _upperBand; - private double _lowerBand; - private double _p_upperBand; - private double _p_lowerBand; + private readonly double _beta; + private double _upperBand, _lowerBand, _p_upperBand, _p_lowerBand; + private double _prevMa1, _prevDet0, _prevDet1, _prevJma, _p_prevMa1, _p_prevDet0, _p_prevDet1, _p_prevJma; + private double _vSum, _p_vSum; + + + public double UpperBand { get; set; } + public double LowerBand { get; set; } + public double Volty { get; set; } + public double VSum { get; set; } + public double Jma { get; set; } + public double AvgVolty { get; set; } + /// /// Initializes a new instance of the Jvolty class with the specified parameters. @@ -28,22 +36,21 @@ public class Jvolty : AbstractBase /// /// Thrown when period is less than 1. /// - public Jvolty(int period, int vshort = 10) + public Jvolty(int period, int phase = 0) { if (period < 1) { throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1."); } _period = period; - int _vlong = 65; + _phase = Math.Clamp((phase * 0.01) + 1.5, 0.5, 2.5); - _values = new CircularBuffer(period); - _voltyShort = new CircularBuffer(vshort); - _vsumBuff = new CircularBuffer(_vlong); - _avoltyBuff = new CircularBuffer(2); + _vsumBuff = new CircularBuffer(10); + _avoltyBuff = new CircularBuffer(65); + _beta = 0.45 * (period - 1) / (0.45 * (period - 1) + 2); WarmupPeriod = period * 2; - Name = $"JVOLTY({period},{vshort})"; + Name = $"JVOLTY({period})"; } /// @@ -53,7 +60,7 @@ public Jvolty(int period, int vshort = 10) /// The period over which to calculate the Jvolty. /// The phase parameter for the JMA-style calculation. /// The short-term volatility period. - public Jvolty(object source, int period, int vshort = 10) : this(period, vshort) + public Jvolty(object source, int period, int phase = 0) : this(period, phase) { var pubEvent = source.GetType().GetEvent("Pub"); pubEvent?.AddEventHandler(source, new BarSignal(Sub)); @@ -70,8 +77,7 @@ public override void Init() _len1 = Math.Max((Math.Log(Math.Sqrt(_period - 1)) / Math.Log(2.0)) + 2.0, 0); _pow1 = Math.Max(_len1 - 2.0, 0.5); _avoltyBuff.Clear(); - _avoltyBuff.Add(0, true); - _avoltyBuff.Add(0, true); + _vsumBuff.Clear(); } /// @@ -85,11 +91,21 @@ protected override void ManageState(bool isNew) _index++; _p_upperBand = _upperBand; _p_lowerBand = _lowerBand; + _p_vSum = _vSum; + _p_prevMa1 = _prevMa1; + _p_prevDet0 = _prevDet0; + _p_prevDet1 = _prevDet1; + _p_prevJma = _prevJma; } else { _upperBand = _p_upperBand; _lowerBand = _p_lowerBand; + _vSum = _p_vSum; + _prevMa1 = _p_prevMa1; + _prevDet0 = _p_prevDet0; + _prevDet1 = _p_prevDet1; + _prevJma = _p_prevJma; } } @@ -101,41 +117,57 @@ protected override void ManageState(bool isNew) /// protected override double Calculation() { - ManageState(BarInput.IsNew); - - _values.Add(BarInput.Close, BarInput.IsNew); + ManageState(Input.IsNew); + double price = Input.Value; if (_index == 1) { - return 0; + _upperBand = _lowerBand = price; } - double hprice = _values.Max(); - double lprice = _values.Min(); - - double del1 = hprice - _upperBand; - double del2 = lprice - _lowerBand; + double del1 = price - _upperBand; + double del2 = price - _lowerBand; double volty = Math.Max(Math.Abs(del1), Math.Abs(del2)); - _voltyShort.Add(volty, BarInput.IsNew); - double vsum = _vsumBuff.Newest() + 0.1 * (volty - _voltyShort.Oldest()); - _vsumBuff.Add(vsum, BarInput.IsNew); + _vsumBuff.Add(volty, Input.IsNew); + _vSum += (_vsumBuff[^1] - _vsumBuff[0]) / 10; + _avoltyBuff.Add(_vSum, Input.IsNew); + double avgvolty = _avoltyBuff.Average(); + + double rvolty = (avgvolty > 0) ? volty / avgvolty : 1; + rvolty = Math.Min(Math.Max(rvolty, 1.0), Math.Pow(_len1, 1.0 / _pow1)); - double prevAvolty = _avoltyBuff.Newest(); - double avolty = prevAvolty + 2.0 / (Math.Max(4.0 * _period, 30) + 1.0) * (vsum - prevAvolty); - _avoltyBuff.Add(avolty, BarInput.IsNew); + double pow2 = Math.Pow(rvolty, _pow1); + double Kv = Math.Pow(_beta, Math.Sqrt(pow2)); - double dVolty = (avolty > 0) ? volty / avolty : 0; - dVolty = Math.Min(Math.Max(dVolty, 1.0), Math.Pow(_len1, 1.0 / _pow1)); + _upperBand = (del1 >= 0) ? price : price - (Kv * del1); + _lowerBand = (del2 <= 0) ? price : price - (Kv * del2); - double pow2 = Math.Pow(dVolty, _pow1); - double len2 = Math.Sqrt(0.5 * (_period - 1)) * _len1; - double Kv = Math.Pow(len2 / (len2 + 1), Math.Sqrt(pow2)); - _upperBand = (del1 > 0) ? hprice : hprice - (Kv * del1); - _lowerBand = (del2 < 0) ? lprice : lprice - (Kv * del2); + + double alpha = Math.Pow(_beta, pow2); + double ma1 = (1 - alpha) * Input.Value + alpha * _prevMa1; + _prevMa1 = ma1; + + double det0 = (price - ma1) * (1 - _beta) + _beta * _prevDet0; + _prevDet0 = det0; + double ma2 = ma1 + _phase * det0; + + double det1 = ((ma2 - _prevJma) * (1 - alpha) * (1 - alpha) ) + (alpha * alpha * _prevDet1); + _prevDet1 = det1; + double jma = _prevJma + det1; + _prevJma = jma; + + UpperBand = _upperBand; + LowerBand = _lowerBand; + Volty = volty; + VSum = _vSum; + AvgVolty = avgvolty; + Jma = jma; IsHot = _index >= WarmupPeriod; return volty; } } + + diff --git a/lib/volatility/todo.md b/lib/volatility/todo.md index 5a4aa17..4a04ca3 100644 --- a/lib/volatility/todo.md +++ b/lib/volatility/todo.md @@ -18,11 +18,11 @@ ## OHLC Input (Open, High, Low, Close) +- **Average True Range (ATR) (High, Low, Close)** - Garman-Klass Volatility - Rogers-Satchell Volatility - Yang-Zhang Volatility - Parkinson Volatility (High, Low) -- Average True Range (ATR) (High, Low, Close) - Chaikin Volatility (High, Low) - Keltner Channels (typically Close, High, Low) - High-Low Volatility (High, Low) diff --git a/notebooks/jma.dib b/notebooks/jma.dib index ed284f0..b6d42f8 100644 --- a/notebooks/jma.dib +++ b/notebooks/jma.dib @@ -82,58 +82,77 @@ TSeries MarketJMA = new() { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, #!csharp -public class Jma1 : AbstractBase +public class Jmaxx : AbstractBase { - public readonly int Period; + private readonly double _period; private readonly double _phase; - private readonly int _vshort, _vlong; - private CircularBuffer _voltyShort; - private CircularBuffer _vsumBuff; - private CircularBuffer _avoltyBuff; - - private double _beta, _len1, _pow1; - private double _upperBand, _lowerBand, _prevMa1, _prevDet0, _prevDet1, _prevJma; - private double _p_UpperBand, _p_LowerBand, _p_prevMa1, _p_prevDet0, _p_prevDet1, _p_prevJma; - - public Jma1(int period, double phase = 0, int vshort = 10) : base() + private readonly CircularBuffer _vsumBuff; + private readonly CircularBuffer _avoltyBuff; + + private double _len1; + private double _pow1; + private readonly double _beta; + private double _upperBand, _lowerBand, _p_upperBand, _p_lowerBand; + private double _prevMa1, _prevDet0, _prevDet1, _prevJma, _p_prevMa1, _p_prevDet0, _p_prevDet1, _p_prevJma; + private double _vSum, _p_vSum; + + + public double UpperBand { get; set; } + public double LowerBand { get; set; } + public double Volty { get; set; } + + /// + /// Initializes a new instance of the Jma class with the specified parameters. + /// + /// The period over which to calculate the Jvolty. + /// The phase parameter for the JMA-style calculation. + /// + /// Thrown when period is less than 1. + /// + public Jmaxx(int period, int phase = 0) { if (period < 1) { throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1."); } - Period = period; - _vshort = vshort; - _vlong = 65; + _period = period; + _phase = Math.Clamp((phase * 0.01) + 1.5, 0.5, 2.5); - _voltyShort = new CircularBuffer(vshort); - _vsumBuff = new CircularBuffer(_vlong); - _avoltyBuff = new CircularBuffer(2); + _vsumBuff = new CircularBuffer(10); + _avoltyBuff = new CircularBuffer(65); + _beta = 0.45 * (_period - 1) / (0.45 * (_period - 1) + 2); - Name = "JMA"; - WarmupPeriod = period * 2; - Init(); + WarmupPeriod = (int)_period * 2; + Name = $"JMA({period})"; } + /// + /// Initializes the Jma instance by setting up the initial state. + /// public override void Init() { - _upperBand = _lowerBand = _prevMa1 = _prevDet0 = _prevDet1 = _prevJma = 0.0; - _p_UpperBand = _p_LowerBand = _p_prevMa1 = _p_prevDet0 = _p_prevDet1 = _p_prevJma = 0.0; - _avoltyBuff.Clear(); - _avoltyBuff.Add(0, true); - _avoltyBuff.Add(0, true); base.Init(); + _upperBand = _lowerBand = 0.0; + _p_upperBand = _p_lowerBand = 0.0; + _len1 = Math.Max((Math.Log(Math.Sqrt(_period - 1)) / Math.Log(2.0)) + 2.0, 0); + _pow1 = Math.Max(_len1 - 2.0, 0.5); + _avoltyBuff.Clear(); + _vsumBuff.Clear(); } + /// + /// Manages the state of the Jma instance based on whether a new value is being processed. + /// + /// Indicates whether the current input is a new value. protected override void ManageState(bool isNew) { if (isNew) { - _lastValidValue = Input.Value; _index++; - // Save current state - _p_UpperBand = _upperBand; - _p_LowerBand = _lowerBand; + _p_upperBand = _upperBand; + _p_lowerBand = _lowerBand; + _p_vSum = _vSum; _p_prevMa1 = _prevMa1; _p_prevDet0 = _prevDet0; _p_prevDet1 = _prevDet1; @@ -141,66 +160,73 @@ public class Jma1 : AbstractBase } else { - // Restore previous state - _upperBand = _p_UpperBand; - _lowerBand = _p_LowerBand; + _upperBand = _p_upperBand; + _lowerBand = _p_lowerBand; + _vSum = _p_vSum; _prevMa1 = _p_prevMa1; _prevDet0 = _p_prevDet0; _prevDet1 = _p_prevDet1; _prevJma = _p_prevJma; - } } + + /// + /// Performs the Jma calculation for the current value. + /// + /// + /// The calculated Jma value for the current input. + /// protected override double Calculation() { ManageState(Input.IsNew); + double price = Input.Value; if (_index == 1) { - _prevMa1 = _prevJma = Input.Value; - return Input.Value; + _upperBand = _lowerBand = price; } - double del1 = Input.Value - _upperBand; - double del2 = Input.Value - _lowerBand; + double del1 = price - _upperBand; + double del2 = price - _lowerBand; double volty = Math.Max(Math.Abs(del1), Math.Abs(del2)); - _voltyShort.Add(volty, Input.IsNew); - double vsum = _vsumBuff.Newest() + 0.1 * (volty - _voltyShort.Oldest()); - _vsumBuff.Add(vsum, Input.IsNew); + _vsumBuff.Add(volty, Input.IsNew); + _vSum += (_vsumBuff[^1] - _vsumBuff[0]) / 10; + _avoltyBuff.Add(_vSum, Input.IsNew); + double avgvolty = _avoltyBuff.Average(); + + double rvolty = (avgvolty > 0) ? volty / avgvolty : 1; + rvolty = Math.Min(Math.Max(rvolty, 1.0), Math.Pow(_len1, 1.0 / _pow1)); + + double pow2 = Math.Pow(rvolty, _pow1); + double Kv = Math.Pow(_beta, Math.Sqrt(pow2)); - double avolty = 0; - for (int i = 0; i < _vsumBuff.Count; i++) { avolty += _vsumBuff[i]; } - avolty /= _vsumBuff.Count; + _upperBand = (del1 >= 0) ? price : price - (Kv * del1); + _lowerBand = (del2 <= 0) ? price : price - (Kv * del2); - double rVolty = (avolty > 0) ? volty / avolty *20: 0; - double _len1 = Math.Max((Math.Log(Math.Sqrt(Period)) / Math.Log(2.0)) + 2.0, 0); - double _pow1 = Math.Max(_len1 - 2, 0.5); - rVolty = Math.Clamp(rVolty, 1.0, Math.Pow(_len1, 1.0 / _pow1)); - double _pow2 = Math.Pow(rVolty, _pow1); - double _beta = 0.45 * (Period - 1) / (0.45 * (Period - 1) + 2); - double len2 = Math.Sqrt(0.5 * (Period - 1)) * _len1; - double _Kv = Math.Pow (_beta, Math.Sqrt(_pow2)) *1.5; - _upperBand = (del1 > 0) ? Input.Value : Input.Value - (_Kv * del1); - _lowerBand = (del2 < 0) ? Input.Value : Input.Value - (_Kv * del2); - double alpha = Math.Pow(_beta, _pow2); - double ma1 = alpha * (_prevMa1 - Input.Value) + Input.Value; + + double alpha = Math.Pow(_beta, pow2); + double ma1 = (1 - alpha) * Input.Value + alpha * _prevMa1; _prevMa1 = ma1; - double det0 = _beta * (_prevDet0 - Input.Value + ma1) + Input.Value - ma1; + double det0 = (price - ma1) * (1 - _beta) + _beta * _prevDet0; _prevDet0 = det0; double ma2 = ma1 + _phase * det0; - double det1 = ((1 - alpha) * (1 - alpha) * (ma2 - _prevJma)) + (alpha * alpha * _prevDet1 ); + double det1 = ((ma2 - _prevJma) * (1 - alpha) * (1 - alpha) ) + (alpha * alpha * _prevDet1); _prevDet1 = det1; double jma = _prevJma + det1; _prevJma = jma; + UpperBand = _upperBand; + LowerBand = _lowerBand; + Volty = volty; + IsHot = _index >= WarmupPeriod; return jma; } @@ -208,22 +234,17 @@ public class Jma1 : AbstractBase #!csharp -TSeries ma = Triangle; -TSeries re = TriangleJMA; +TSeries ma = Complex; +TSeries re = ComplexJMA; TSeries out1 = new(); -TSeries out2 = new(); -Jma calc = new(10); -Jma1 calc1 = new(10); + +Jmaxx calc = new(10); + foreach (var value in ma) { out1.Add(calc.Calc(value)); } -foreach (var value in ma) { out2.Add(calc1.Calc(value)); } + Plot plt = new(); var sigplot = plt.Add.Signal(ma.v.ToArray()[60..80]); var jmaplot = plt.Add.Signal(re.v.ToArray()[60..80]); sigplot.Color = ScottPlot.Colors.Red; sigplot.LineWidth = 2; jmaplot.LineWidth = 3; -//var jma1plot = plt.Add.Signal(out1.v.ToArray()[60..80]); jma1plot.Color = ScottPlot.Colors.Purple; jma1plot.LineWidth = 3; -var jma2plot = plt.Add.Signal(out2.v.ToArray()[60..80]); jma2plot.Color = ScottPlot.Colors.Blue; jma2plot.LineWidth = 3; -plt.Display(); - -#!csharp +var jma1plot = plt.Add.Signal(out1.v.ToArray()[60..80]); jma1plot.Color = ScottPlot.Colors.Purple; jma1plot.LineWidth = 3; -#r "nuget: Plotly.net.Interactive" -using Plotly.NET.Interactive; +plt.Display(); diff --git a/quantower/Averages/JmaIndicator.cs b/quantower/Averages/JmaIndicator.cs index 049aa19..e661c9d 100644 --- a/quantower/Averages/JmaIndicator.cs +++ b/quantower/Averages/JmaIndicator.cs @@ -9,7 +9,7 @@ public class JmaIndicator : Indicator, IWatchlistIndicator public int Periods { get; set; } = 10; [InputParameter("Phase", sortIndex: 2, -100, 100, 1, 0)] - public double Phase { get; set; } = 0; + public int Phase { get; set; } = 0; [InputParameter("Data source", sortIndex: 4, variants: [ "Open", SourceType.Open, diff --git a/quantower/Averages/MacdIndicator.cs b/quantower/Averages/MacdIndicator.cs new file mode 100644 index 0000000..8dca5e3 --- /dev/null +++ b/quantower/Averages/MacdIndicator.cs @@ -0,0 +1,95 @@ +using System.Diagnostics.Metrics; +using System.Drawing; +using TradingPlatform.BusinessLayer; + +namespace QuanTAlib; + +public class MacdIndicator : Indicator, IWatchlistIndicator +{ + [InputParameter("Slow EMA", sortIndex: 1, 1, 1000, 1, 0)] + public int Slow { get; set; } = 26; + + [InputParameter("Fast EMA", sortIndex: 2, 1, 2000, 1, 0)] + public int Fast { get; set; } = 12; + + [InputParameter("Signal line", sortIndex: 3, 1, 2000, 1, 0)] + public int Signal { get; set; } = 9; + + [InputParameter("Use SMA for warmup period", sortIndex: 2)] + public bool UseSMA { get; set; } = false; + + [InputParameter("Data source", sortIndex: 3, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; + + [InputParameter("Show cold values", sortIndex: 21)] + public bool ShowColdValues { get; set; } = true; + + private Ema? slow_ma; + private Ema? fast_ma; + private Ema? signal_ma; + protected LineSeries? MainSeries; + protected LineSeries? SignalSeries; + + protected string? SourceName; + public int MinHistoryDepths => Slow; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + + public override string ShortName => $"MACD {Slow}:{Fast}:{Signal}"; + + public MacdIndicator() + { + OnBackGround = true; + SeparateWindow = true; + SourceName = Source.ToString(); + Name = "MACD - Moving Average Convergence Divergence"; + Description = "MACD"; + MainSeries = new(name: $"MAIN", color: Color.Yellow, width: 2, style: LineStyle.Solid); + SignalSeries = new(name: $"SIGNAL", color: Color.Blue, width: 2, style: LineStyle.Solid); + + AddLineSeries(MainSeries); + AddLineSeries(SignalSeries); + } + + protected override void OnInit() + { + slow_ma = new(Slow, useSma: UseSMA); + fast_ma = new(Fast, useSma: UseSMA); + signal_ma = new(Signal, useSma: UseSMA); + SourceName = Source.ToString(); + base.OnInit(); + } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + slow_ma!.Calc(input); + fast_ma!.Calc(input); + double main = fast_ma.Value - slow_ma.Value; + signal_ma!.Calc(main); + + MainSeries!.SetValue(main); + MainSeries!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here + SignalSeries!.SetValue(signal_ma.Value); + SignalSeries!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here + } + + public override void OnPaintChart(PaintChartEventArgs args) + { + base.OnPaintChart(args); + this.PaintSmoothCurve(args, MainSeries!, slow_ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.PaintSmoothCurve(args, SignalSeries!, slow_ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + this.DrawText(args, Description); + } +} + diff --git a/quantower/Volatility/JbandsIndicator.cs b/quantower/Volatility/JbandsIndicator.cs new file mode 100644 index 0000000..608f93c --- /dev/null +++ b/quantower/Volatility/JbandsIndicator.cs @@ -0,0 +1,64 @@ +using System.Drawing; +using TradingPlatform.BusinessLayer; + +namespace QuanTAlib; + +public class JbandsIndicator : Indicator, IWatchlistIndicator +{ + [InputParameter("Periods", sortIndex: 1, 1, 2000, 1, 0)] + public int Periods { get; set; } = 14; + + [InputParameter("Data source", sortIndex: 5, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; + + [InputParameter("vShort", sortIndex: 6, -100, 100, 1, 0)] + public int Phase { get; set; } = 10; + + private Jma? jma; + protected LineSeries? UbSeries; + protected LineSeries? LbSeries; + protected string? SourceName; + public static int MinHistoryDepths => 2; + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; + + public JbandsIndicator() + { + Name = "JBANDS - Mark Jurik's Bands"; + Description = "Upper and Lower Bands."; + SeparateWindow = false; + + UbSeries = new("UB", Color.Blue, 2, LineStyle.Solid); + LbSeries = new("LB", Color.Red, 2, LineStyle.Solid); + AddLineSeries(UbSeries); + AddLineSeries(LbSeries); + } + + protected override void OnInit() + { + jma = new(Periods, phase: Phase); + SourceName = Source.ToString(); + base.OnInit(); + } + + protected override void OnUpdate(UpdateArgs args) + { + TValue input = this.GetInputValue(args, Source); + jma!.Calc(input); + + UbSeries!.SetValue(jma.UpperBand); + LbSeries!.SetValue(jma.LowerBand); + } + + public override string ShortName => $"JBands ({Periods}:{Phase})"; +} diff --git a/quantower/Volatility/JvoltyIndicator.cs b/quantower/Volatility/JvoltyIndicator.cs index 9db2334..7a6436b 100644 --- a/quantower/Volatility/JvoltyIndicator.cs +++ b/quantower/Volatility/JvoltyIndicator.cs @@ -6,11 +6,27 @@ namespace QuanTAlib; public class JvoltyIndicator : Indicator, IWatchlistIndicator { [InputParameter("Periods", sortIndex: 1, 1, 2000, 1, 0)] - public int Periods { get; set; } = 20; - - private Jvolty? jvolty; + public int Periods { get; set; } = 14; + + [InputParameter("Data source", sortIndex: 5, variants: [ + "Open", SourceType.Open, + "High", SourceType.High, + "Low", SourceType.Low, + "Close", SourceType.Close, + "HL/2 (Median)", SourceType.HL2, + "OC/2 (Midpoint)", SourceType.OC2, + "OHL/3 (Mean)", SourceType.OHL3, + "HLC/3 (Typical)", SourceType.HLC3, + "OHLC/4 (Average)", SourceType.OHLC4, + "HLCC/4 (Weighted)", SourceType.HLCC4 + ])] + public SourceType Source { get; set; } = SourceType.Close; + + private Jma? jma; protected LineSeries? JvoltySeries; public static int MinHistoryDepths => 2; + + int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; public JvoltyIndicator() @@ -25,16 +41,17 @@ public JvoltyIndicator() protected override void OnInit() { - jvolty = new (Periods); + jma = new(Periods); base.OnInit(); } protected override void OnUpdate(UpdateArgs args) { - TBar input = IndicatorExtensions.GetInputBar(this, args); - TValue result = jvolty!.Calc(input); + TValue input = this.GetInputValue(args, Source); + jma!.Calc(input); + + JvoltySeries!.SetValue(jma.Volty); - JvoltySeries!.SetValue(result.Value); } public override string ShortName => $"JVOLTY ({Periods})";