-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
325 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
using Xunit; | ||
using System.Security.Cryptography; | ||
|
||
namespace QuanTAlib.Tests; | ||
|
||
public class VolatilityUpdateTests | ||
{ | ||
private readonly RandomNumberGenerator rng = RandomNumberGenerator.Create(); | ||
private const int RandomUpdates = 100; | ||
private const double ReferenceValue = 100.0; | ||
private const int precision = 8; | ||
|
||
private double GetRandomDouble() | ||
{ | ||
byte[] bytes = new byte[8]; | ||
rng.GetBytes(bytes); | ||
return (double)BitConverter.ToUInt64(bytes, 0) / ulong.MaxValue * 200 - 100; // Range: -100 to 100 | ||
} | ||
|
||
private TBar GetRandomBar(bool IsNew) | ||
{ | ||
double open = GetRandomDouble(); | ||
double high = open + Math.Abs(GetRandomDouble()); | ||
double low = open - Math.Abs(GetRandomDouble()); | ||
double close = low + (high - low) * GetRandomDouble(); | ||
return new TBar(DateTime.Now, open, high, low, close, 1000, IsNew); | ||
} | ||
|
||
[Fact] | ||
public void Atr_Update() | ||
{ | ||
var indicator = new Atr(period: 14); | ||
TBar r = GetRandomBar(true); | ||
double initialValue = indicator.Calc(r); | ||
|
||
for (int i = 0; i < RandomUpdates; i++) | ||
{ | ||
indicator.Calc(GetRandomBar(IsNew: false)); | ||
} | ||
double finalValue = indicator.Calc(new TBar(r.Time, r.Open, r.High, r.Low, r.Close, r.Volume, IsNew: false)); | ||
|
||
Assert.Equal(initialValue, finalValue, precision); | ||
} | ||
|
||
[Fact] | ||
public void Historical_Update() | ||
{ | ||
var indicator = new Historical(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 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() | ||
{ | ||
var indicator = new Realized(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 Rvi_Update() | ||
{ | ||
var indicator = new Rvi(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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
/// <summary> | ||
/// Represents a Jurik Volatility (Jvolty) calculator, a measure of market volatility based on Jurik Moving Average (JMA) concepts. | ||
/// </summary> | ||
|
||
namespace QuanTAlib; | ||
|
||
public class Jvolty : AbstractBase | ||
{ | ||
private readonly int _period; | ||
private readonly CircularBuffer _values; | ||
private readonly CircularBuffer _voltyShort; | ||
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; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the Jvolty class with the specified parameters. | ||
/// </summary> | ||
/// <param name="period">The period over which to calculate the Jvolty.</param> | ||
/// <param name="phase">The phase parameter for the JMA-style calculation.</param> | ||
/// <param name="vshort">The short-term volatility period.</param> | ||
/// <exception cref="ArgumentOutOfRangeException"> | ||
/// Thrown when period is less than 1. | ||
/// </exception> | ||
public Jvolty(int period, int vshort = 10) | ||
{ | ||
if (period < 1) | ||
{ | ||
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1."); | ||
} | ||
_period = period; | ||
int _vlong = 65; | ||
|
||
_values = new CircularBuffer(period); | ||
_voltyShort = new CircularBuffer(vshort); | ||
_vsumBuff = new CircularBuffer(_vlong); | ||
_avoltyBuff = new CircularBuffer(2); | ||
|
||
WarmupPeriod = period * 2; | ||
Name = $"JVOLTY({period},{vshort})"; | ||
} | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the Jvolty class with the specified source and parameters. | ||
/// </summary> | ||
/// <param name="source">The source object to subscribe to for bar updates.</param> | ||
/// <param name="period">The period over which to calculate the Jvolty.</param> | ||
/// <param name="phase">The phase parameter for the JMA-style calculation.</param> | ||
/// <param name="vshort">The short-term volatility period.</param> | ||
public Jvolty(object source, int period, int vshort = 10) : this(period, vshort) | ||
{ | ||
var pubEvent = source.GetType().GetEvent("Pub"); | ||
pubEvent?.AddEventHandler(source, new BarSignal(Sub)); | ||
} | ||
|
||
/// <summary> | ||
/// Initializes the Jvolty instance by setting up the initial state. | ||
/// </summary> | ||
public override void Init() | ||
{ | ||
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); | ||
} | ||
|
||
/// <summary> | ||
/// Manages the state of the Jvolty instance based on whether a new bar is being processed. | ||
/// </summary> | ||
/// <param name="isNew">Indicates whether the current input is a new bar.</param> | ||
protected override void ManageState(bool isNew) | ||
{ | ||
if (isNew) | ||
{ | ||
_index++; | ||
_p_upperBand = _upperBand; | ||
_p_lowerBand = _lowerBand; | ||
} | ||
else | ||
{ | ||
_upperBand = _p_upperBand; | ||
_lowerBand = _p_lowerBand; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Performs the Jvolty calculation for the current bar. | ||
/// </summary> | ||
/// <returns> | ||
/// The calculated Jvolty value for the current bar. | ||
/// </returns> | ||
protected override double Calculation() | ||
{ | ||
ManageState(BarInput.IsNew); | ||
|
||
_values.Add(BarInput.Close, BarInput.IsNew); | ||
|
||
if (_index == 1) | ||
{ | ||
return 0; | ||
} | ||
|
||
double hprice = _values.Max(); | ||
double lprice = _values.Min(); | ||
|
||
double del1 = hprice - _upperBand; | ||
double del2 = lprice - _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); | ||
|
||
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 dVolty = (avolty > 0) ? volty / avolty : 0; | ||
dVolty = Math.Min(Math.Max(dVolty, 1.0), Math.Pow(_len1, 1.0 / _pow1)); | ||
|
||
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); | ||
|
||
IsHot = _index >= WarmupPeriod; | ||
return volty; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
using System.Drawing; | ||
using TradingPlatform.BusinessLayer; | ||
|
||
namespace QuanTAlib; | ||
|
||
public class JvoltyIndicator : Indicator, IWatchlistIndicator | ||
{ | ||
[InputParameter("Periods", sortIndex: 1, 1, 2000, 1, 0)] | ||
public int Periods { get; set; } = 20; | ||
|
||
private Jvolty? jvolty; | ||
protected LineSeries? JvoltySeries; | ||
public static int MinHistoryDepths => 2; | ||
int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths; | ||
|
||
public JvoltyIndicator() | ||
{ | ||
Name = "JVOLTY - Mark Jurik's Volatility"; | ||
Description = "Measures market volatility according to Mark Jurik."; | ||
SeparateWindow = true; | ||
|
||
JvoltySeries = new("JVOLTY", Color.Blue, 2, LineStyle.Solid); | ||
AddLineSeries(JvoltySeries); | ||
} | ||
|
||
protected override void OnInit() | ||
{ | ||
jvolty = new (Periods); | ||
base.OnInit(); | ||
} | ||
|
||
protected override void OnUpdate(UpdateArgs args) | ||
{ | ||
TBar input = IndicatorExtensions.GetInputBar(this, args); | ||
TValue result = jvolty!.Calc(input); | ||
|
||
JvoltySeries!.SetValue(result.Value); | ||
} | ||
|
||
public override string ShortName => $"JVOLTY ({Periods})"; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
sonar.issue.ignore.multicriteria=s1944,s2053,s2222,s2259,s2583,s2589,s3329,s3655,s3900,s3949,s3966,s4158,s4347,s5773,s6781 | ||
|
||
sonar.issue.ignore.multicriteria.s1944.ruleKey=S1944 | ||
sonar.issue.ignore.multicriteria.s2053.ruleKey=S2053 | ||
sonar.issue.ignore.multicriteria.s2222.ruleKey=S2222 | ||
sonar.issue.ignore.multicriteria.s2259.ruleKey=S2259 | ||
sonar.issue.ignore.multicriteria.s2583.ruleKey=S2583 | ||
sonar.issue.ignore.multicriteria.s2589.ruleKey=S2589 | ||
sonar.issue.ignore.multicriteria.s3329.ruleKey=S3329 | ||
sonar.issue.ignore.multicriteria.s3655.ruleKey=S3655 | ||
sonar.issue.ignore.multicriteria.s3900.ruleKey=S3900 | ||
sonar.issue.ignore.multicriteria.s3949.ruleKey=S3949 | ||
sonar.issue.ignore.multicriteria.s3966.ruleKey=S3966 | ||
sonar.issue.ignore.multicriteria.s4158.ruleKey=S4158 | ||
sonar.issue.ignore.multicriteria.s4347.ruleKey=S4347 | ||
sonar.issue.ignore.multicriteria.s5773.ruleKey=S5773 | ||
sonar.issue.ignore.multicriteria.s6781.ruleKey=S6781 | ||
|
||
sonar.issue.ignore.multicriteria.s1944.resourceKey=**/* | ||
sonar.issue.ignore.multicriteria.s2053.resourceKey=**/* | ||
sonar.issue.ignore.multicriteria.s2222.resourceKey=**/* | ||
sonar.issue.ignore.multicriteria.s2259.resourceKey=**/* | ||
sonar.issue.ignore.multicriteria.s2583.resourceKey=**/* | ||
sonar.issue.ignore.multicriteria.s2589.resourceKey=**/* | ||
sonar.issue.ignore.multicriteria.s3329.resourceKey=**/* | ||
sonar.issue.ignore.multicriteria.s3655.resourceKey=**/* | ||
sonar.issue.ignore.multicriteria.s3900.resourceKey=**/* | ||
sonar.issue.ignore.multicriteria.s3949.resourceKey=**/* | ||
sonar.issue.ignore.multicriteria.s3966.resourceKey=**/* | ||
sonar.issue.ignore.multicriteria.s4158.resourceKey=**/* | ||
sonar.issue.ignore.multicriteria.s4347.resourceKey=**/* | ||
sonar.issue.ignore.multicriteria.s5773.resourceKey=**/* | ||
sonar.issue.ignore.multicriteria.s6781.resourceKey=**/* |