JMA finalization

This commit is contained in:
Miha Kralj
2023-03-30 14:44:05 -07:00
parent 38c920c49d
commit 468ea7a0af
10 changed files with 198 additions and 141 deletions
@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<AnalysisInput xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Settings>
<Setting>
<Key>sonar.cs.analyzeGeneratedCode</Key>
<Value>false</Value>
</Setting>
<Setting>
<Key>sonar.cs.file.suffixes</Key>
<Value>.cs</Value>
</Setting>
<Setting>
<Key>sonar.cs.ignoreHeaderComments</Key>
<Value>true</Value>
</Setting>
<Setting>
<Key>sonar.cs.roslyn.ignoreIssues</Key>
<Value>false</Value>
</Setting>
</Settings>
<Rules>
<Rule>
<Key>S107</Key>
<Parameters>
<Parameter>
<Key>max</Key>
<Value>7</Value>
</Parameter>
</Parameters>
</Rule>
<Rule>
<Key>S110</Key>
<Parameters>
<Parameter>
<Key>max</Key>
<Value>5</Value>
</Parameter>
</Parameters>
</Rule>
<Rule>
<Key>S1479</Key>
<Parameters>
<Parameter>
<Key>maximum</Key>
<Value>30</Value>
</Parameter>
</Parameters>
</Rule>
<Rule>
<Key>S2342</Key>
<Parameters>
<Parameter>
<Key>flagsAttributeFormat</Key>
<Value>^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?s$</Value>
</Parameter>
<Parameter>
<Key>format</Key>
<Value>^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?$</Value>
</Parameter>
</Parameters>
</Rule>
<Rule>
<Key>S2436</Key>
<Parameters>
<Parameter>
<Key>max</Key>
<Value>2</Value>
</Parameter>
<Parameter>
<Key>maxMethod</Key>
<Value>3</Value>
</Parameter>
</Parameters>
</Rule>
<Rule>
<Key>S3776</Key>
<Parameters>
<Parameter>
<Key>propertyThreshold</Key>
<Value>3</Value>
</Parameter>
<Parameter>
<Key>threshold</Key>
<Value>15</Value>
</Parameter>
</Parameters>
</Rule>
</Rules>
</AnalysisInput>
@@ -380,6 +380,7 @@
<Rule Id="S6423" Action="None" />
<Rule Id="S6424" Action="None" />
<Rule Id="S6507" Action="None" />
<Rule Id="S6513" Action="None" />
<Rule Id="S818" Action="Info" />
<Rule Id="S881" Action="None" />
<Rule Id="S907" Action="Warning" />
+15 -13
View File
@@ -8,17 +8,22 @@ namespace QuanTAlib;
public class JMA_chart : Indicator {
#region Parameters
[InputParameter("Smoothing period", 0, 1, 999, 1, 1)]
private int Period = 10;
[InputParameter("Data source", 1, variants: new object[]
[InputParameter("Data source", 0, variants: new object[]
{ "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
"OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
private int DataSource = 3
;
[InputParameter("Slope calc", 2, 2, 10, 1, 1)]
private int SlopePeriod = 3;
private int DataSource = 3;
[InputParameter("Smoothing period", 1, 1, 999, 1, 1)]
private int Period = 10;
[InputParameter("Volatility short", 2, 3, 50, 1, 1)]
private int Vshort = 10;
[InputParameter("Volatility long", 3, 20, 500, 1, 1)]
private int Vlong = 65;
[InputParameter("Phase", 4, -100, 100, 1, 2)]
private double Jphase = 0.0;
#endregion Parameters
@@ -26,21 +31,19 @@ public class JMA_chart : Indicator {
///////
private JMA_Series indicator;
private LINREG_Series slope;
///////
public JMA_chart() {
this.SeparateWindow = false;
this.Name = "JMA - Jurik Moving Avg";
this.Description = "Jurik Moving Average description";
this.AddLineSeries("JMA", Color.Blue, 4, LineStyle.Solid);
this.AddLineSeries("JMA", Color.Yellow, 3, LineStyle.Solid);
}
protected override void OnInit() {
this.bars = new();
this.indicator = new(source: bars.Select(this.DataSource), period: this.Period, useNaN: false);
this.slope = new(source: this.indicator, period: this.SlopePeriod);
this.indicator = new(source: bars.Select(this.DataSource), period: this.Period, phase: Jphase, vshort: Vshort, vlong: Vlong, useNaN: false);
}
protected override void OnUpdate(UpdateArgs args) {
@@ -51,7 +54,6 @@ public class JMA_chart : Indicator {
this.GetPrice(PriceType.Close), this.GetPrice(PriceType.Volume), update);
double result = this.indicator[this.indicator.Count - 1].v;
this.LinesSeries[0].SetMarker(offset: 0,color: this.slope > 0 ? Color.FromArgb(0,160,0) : Color.FromArgb(255, 0, 0));
this.SetValue(result, lineIndex: 0);
}
}
+11 -10
View File
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net48</TargetFramework>
<TargetFramework>net6</TargetFramework>
<LangVersion>preview</LangVersion>
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<Platforms>AnyCPU</Platforms>
<AlgoType>Indicator</AlgoType>
<AssemblyName>Quantower_QTAlib</AssemblyName>
@@ -21,9 +21,7 @@
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<PlatformTarget>anycpu</PlatformTarget>
<DebugType>full</DebugType>
<!--
<OutputPath>C:\Quantower\TradingPlatform\v1.129.11\..\..\Settings\Scripts\Indicators\Quantower</OutputPath>
-->
<OutputPath>C:\Quantower\TradingPlatform\v1.130.7\..\..\Settings\Scripts\Indicators\Quantower</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>embedded</DebugType>
@@ -31,21 +29,24 @@
<WarningLevel>3</WarningLevel>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<PlatformTarget>anycpu</PlatformTarget>
<!--
<OutputPath>C:\Quantower\TradingPlatform\v1.129.11\..\..\Settings\Scripts\Indicators\Quantower</OutputPath>
-->
<OutputPath>C:\Quantower\TradingPlatform\v1.130.7\..\..\Settings\Scripts\Indicators\Quantower</OutputPath>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Source\**\*.cs" Exclude="..\Source\obj\**;..\Source\Feeds\**">
<Link>QuanTAlib\%(RecursiveDir)%(Filename)%(Extension)</Link>
</Compile>
</ItemGroup>
<!--
<Target Name="CopyCustomContent" AfterTargets="AfterBuild">
<Copy SourceFiles=".\bin\$(Configuration)\net48\Quantower_QTAlib.dll" DestinationFolder="\Quantower\Settings\Scripts\Indicators\QuanTAlib" />
<Copy SourceFiles=".\bin\$(Configuration)\net7\Quantower_QTAlib.dll" DestinationFolder="\Quantower\Settings\Scripts\Indicators\QuanTAlib" />
</Target>
-->
<ItemGroup>
<AdditionalFiles Include="..\.sonarlint\mihakralj_quantalib\CSharp\SonarLint.xml" Link="SonarLint.xml" />
</ItemGroup>
<ItemGroup>
<Reference Include="TradingPlatform.BusinessLayer">
<HintPath>C:\Quantower\TradingPlatform\v1.129.11\bin\TradingPlatform.BusinessLayer.dll</HintPath>
<HintPath>C:\Quantower\TradingPlatform\v1.130.7\bin\TradingPlatform.BusinessLayer.dll</HintPath>
</Reference>
</ItemGroup>
</Project>
Binary file not shown.
+20 -21
View File
@@ -23,30 +23,29 @@ public abstract class Single_TSeries_Indicator : TSeries
protected readonly TSeries _data;
protected int _p;
// Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN)
protected Single_TSeries_Indicator(TSeries source, int period, bool useNaN)
{
this._data = source;
this._period = period;
this._p = _period;
this._NaN = useNaN;
this._data.Pub += this.Sub;
}
// Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN)
protected Single_TSeries_Indicator(TSeries source, int period, bool useNaN) {
_data = source;
_period = period;
_p = _period;
_NaN = useNaN;
_data.Pub += Sub;
}
// overridable Add() method to add/update a single item at the end of the list
// overridable Add() method to add/update a single item at the end of the list
public virtual void Add((System.DateTime t, double v) TValue, bool update, bool useNaN)
{
if (_period == 0) { _p = this.Length; }
var res = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : TValue.v);
base.Add(res, update);
}
public new virtual void Add((System.DateTime t, double v) TValue, bool update) => base.Add(TValue, update);
public virtual void Add((DateTime t, double v) TValue, bool update, bool useNaN) {
if (_period == 0) { _p = Length; }
var res = (TValue.t, Count < _p - 1 && _NaN ? double.NaN : TValue.v);
base.Add(res, update);
}
public new virtual void Add((DateTime t, double v) TValue, bool update) => base.Add(TValue, update);
// potentially overridable Add() method for the whole series (could be replaced with faster bulk algo)
public virtual void Add(TSeries data) { for (int i = 0; i < data.Count; i++) { this.Add(TValue: data[i], update: false); } }
public new void Add((System.DateTime t, double v) TValue) => this.Add(TValue: TValue, update: false);
// potentially overridable Add() method for the whole series (could be replaced with faster bulk algo)
public virtual void Add(TSeries data) {
foreach (var item in data) { Add(TValue: item, update: false); }
}
public new void Add((System.DateTime t, double v) TValue) => this.Add(TValue: TValue, update: false);
public void Add(bool update) => this.Add(TValue: this._data[this._data.Count - 1], update: update);
public void Add() => this.Add(TValue: this._data[this._data.Count - 1], update: false);
public new void Sub(object source, TSeriesEventArgs e) => this.Add(TValue: this._data[this._data.Count - 1], update: e.update);
+35 -76
View File
@@ -1,5 +1,7 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Linq;
/* <summary>
TSeries is the cornerstone of all QuanTAlib classess.
@@ -11,87 +13,44 @@ TSeries is the cornerstone of all QuanTAlib classess.
- includes publishing and subscribing methods that attach to events
</summary> */
public class TSeries : System.Collections.Generic.List<(DateTime t, double v)>
{
// when asked for a (t,v) tuple, return the last (t,v) on the List
public static implicit operator (DateTime t, double v)(TSeries l) => l[l.Count - 1];
public class TSeries : List<(DateTime t, double v)> {
// when asked for a (double), return the value part of the last tuple on the list
public static implicit operator double(TSeries l) => l[l.Count - 1].v;
public static implicit operator (DateTime t, double v)(TSeries l) => l[^1];
public static implicit operator double(TSeries l) => l[^1].v;
public static implicit operator DateTime(TSeries l) => l[^1].t;
public List<DateTime> t => this.Select(item => item.t).ToList();
public List<double> v => this.Select(item => item.v).ToList();
public int Length => this.Count;
// when asked for a (DateTime), return the DateTime part of the last tuple on the list
public static implicit operator DateTime(TSeries l) => l[l.Count - 1].t;
//convert from tuple List(t,v) to single List(DateTime)
public System.Collections.Generic.List<DateTime> t {
get { System.Collections.Generic.List<DateTime> TList = new();
for (int i = 0; i < this.Count; i++) { TList.Add(this[i].t); }
return TList;
}
}
public TSeries Tail(int count = 10) {
var tailSeries = new TSeries();
tailSeries.AddRange(this.Skip(Math.Max(0, this.Count - count)).Take(count));
return tailSeries;
}
public void Add((DateTime t, double v) TValue, bool update = false) {
if (update) { this[^1] = TValue; }
else { base.Add(TValue); }
OnEvent(update);
}
//convert from tuple List(t,v) to single List(double)
public System.Collections.Generic.List<double> v {
get { System.Collections.Generic.List<double> VList = new();
for (int i = 0; i < this.Count; i++) { VList.Add(this[i].v); }
return VList;
}
}
public void Add(DateTime t, double v, bool update = false) => this.Add((t, v), update);
public void Add(double v, bool update = false) => this.Add((DateTime.Now, v), update);
protected virtual void OnEvent(bool update = false) {
Pub?.Invoke(this, new TSeriesEventArgs { update = update }); }
public int Length => this.Count;
public delegate void NewDataEventHandler(object source, TSeriesEventArgs args);
public event NewDataEventHandler Pub;
public TSeries Tail(int count=10) {
TSeries outSeries = new();
if (count > this.Count) { count = this.Count; }
for (int i = this.Count-count; i<this.Count; i++) { outSeries.Add(this[i]); }
return outSeries;
}
// add/update one (t,v) tuple to/at the end of the list
public void Add((DateTime t, double v) TValue, bool update = false)
{
if (update) { this[this.Count - 1] = TValue; }
else { base.Add(TValue); }
this.OnEvent(update);
}
public void Add(DateTime t, double v, bool update = false) => this.Add((t, v), update);
public void Add(double v, bool update = false) => this.Add((DateTime.Now, v), update);
// Broadcast handler - only to valid targets
protected virtual void OnEvent(bool update = false)
{
if (Pub != null && Pub.Target != this)
{
Pub(this, new TSeriesEventArgs { update = update });
}
}
// delegate used by event handler + event handler (Pub == publisher)
public delegate
void NewDataEventHandler(object source, TSeriesEventArgs args);
public event NewDataEventHandler Pub;
public void Sub(object source, TSeriesEventArgs e)
{
TSeries ss = (TSeries)source;
if (ss.Count > 0)
{
for (int i = 0; i < ss.Count; i++)
{
this.Add(ss[i]);
}
}
else
{
this.Add(ss[ss.Count - 1], e.update);
}
}
public void Sub(object source, TSeriesEventArgs e) {
TSeries ss = (TSeries)source;
if (ss.Count > 0) {
this.AddRange(ss);
} else {
Add(ss[^1], e.update);
}
}
}
// EventArgs extension - carries the update field
public class TSeriesEventArgs : EventArgs
{
public bool update { get; set; }
public class TSeriesEventArgs : EventArgs{
public bool update { get; set; }
}
+2 -2
View File
@@ -2,7 +2,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Title>QuanTAlib</Title>
<Version>0.1.29</Version>
<Version>0.1.30</Version>
<Product>Library of Technical Indicators for .NET</Product>
<Description>Quantitative Technical Analysis library for real-time (streaming) data analysis</Description>
<RepositoryType>git</RepositoryType>
@@ -11,7 +11,7 @@
<Authors>Miha Kralj</Authors>
<Copyright>Miha Kralj</Copyright>
<PackageReadmeFile>readme.md</PackageReadmeFile>
<TargetFrameworks>net7.0;net6.0;netstandard2.1;net48</TargetFrameworks>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<LangVersion>preview</LangVersion>
<Nullable>disable</Nullable>
+16 -13
View File
@@ -21,7 +21,7 @@ Issues:
</summary>
*/
public class JMA_Series : Single_TSeries_Indicator {
private readonly System.Collections.Generic.List<double> volty_10 = new();
private readonly System.Collections.Generic.List<double> volty_short = new();
private readonly System.Collections.Generic.List<double> vsum_buff = new();
private readonly double pr;
public TSeries mma1 { get; }
@@ -30,14 +30,17 @@ public class JMA_Series : Single_TSeries_Indicator {
private double upperBand, lowerBand, vsum, Kv, del1, del2;
private double prev_ma1, prev_det0, prev_det1, prev_vsum, prev_jma;
private double p_upperBand, p_lowerBand, p_Kv, p_prev_ma1, p_prev_det0, p_prev_det1, p_prev_vsum, p_prev_jma;
private readonly int _voltyS, _voltyL;
public JMA_Series(TSeries source, int period, double phase = 0.0, bool useNaN = false) : base(source, period, useNaN) {
public JMA_Series(TSeries source, int period, double phase = 0.0, int vshort = 10, int vlong = 65, bool useNaN = false) : base(source, period, useNaN) {
upperBand = lowerBand = prev_ma1 = prev_det0 = prev_det1 = prev_vsum = prev_jma = Kv = del1 = del2 = 0.0;
Kv = 0;
pr = (phase * 0.01) + 1.5;
if (phase < -100) { pr = 0.5; }
if (phase > 100) { pr = 2.5; }
_voltyS = vshort;
_voltyL = vlong;
mma1 = new();
mma2 = new();
@@ -77,32 +80,32 @@ public class JMA_Series : Single_TSeries_Indicator {
if (Math.Abs(del1) < Math.Abs(del2)) { volty = Math.Abs(del2); }
//// from volty to avolty
if (update) { volty_10[volty_10.Count - 1] = volty; }
else { volty_10.Add(volty); }
if (volty_10.Count > 10) { volty_10.RemoveAt(0); }
vsum = prev_vsum + 0.1 * (volty - volty_10.First());
if (update) { volty_short[volty_short.Count - 1] = volty; }
else { volty_short.Add(volty); }
if (volty_short.Count > _voltyS) { volty_short.RemoveAt(0); }
vsum = prev_vsum + 0.1 * (volty - volty_short.First());
prev_vsum = vsum;
if (update) { vsum_buff[vsum_buff.Count - 1] = vsum; }
else { vsum_buff.Add(vsum); }
if (vsum_buff.Count > (10 * _p)) { vsum_buff.RemoveAt(0); }
if (vsum_buff.Count > _voltyL) { vsum_buff.RemoveAt(0); }
double avolty = 0;
for (int i = 0; i < vsum_buff.Count; i++) { avolty += vsum_buff[i]; }
avolty /= vsum_buff.Count;
/// from avolty to rolty
double rvolty = (avolty != 0) ? volty / avolty : 0;
double len1 = (Math.Log(Math.Sqrt(2.0 * _p)) / Math.Log(2.0)) + 2;
if (len1 < 0) len1 = 0;
double len1 = (Math.Log(Math.Sqrt(_p)) / Math.Log(2.0)) + 2;
if (len1 < 0)
len1 = 0;
double pow1 = Math.Max(len1 - 2.0, 0.5);
if (rvolty > Math.Pow(len1, 1.0 / pow1)) { rvolty = Math.Pow(len1, 1.0 / pow1); }
if (rvolty < 1) { rvolty = 1; }
//// from rvolty to second smoothing
double pow2 = Math.Pow(rvolty, pow1);
double len2 = Math.Sqrt(0.5 * (_p - 2)) * len1;
Kv = Math.Pow(len2 / (len2 + 2), Math.Sqrt(pow2));
double beta = 0.45 * (_p - 1) / (0.45 * (_p - 1) + 2);
double alpha = Math.Pow(beta * 1.1, pow2);
Kv = Math.Pow(beta, Math.Sqrt(pow2));
double alpha = Math.Pow(beta, pow2);
double ma1 = (1 - alpha) * TValue.v + alpha * prev_ma1;
prev_ma1 = ma1;
mma1.Add(ma1);
+9 -6
View File
@@ -5,6 +5,8 @@ using Python.Runtime;
using Python.Included;
namespace Validations;
/*
public class PandasTA : IDisposable
{
private readonly GBM_Feed bars;
@@ -144,7 +146,7 @@ public class PandasTA : IDisposable
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
*/
[Fact] void EMA() {
EMA_Series QL = new(bars.Close, period, false);
var pta = df.ta.ema(close: df.close, length: period);
@@ -155,7 +157,7 @@ public class PandasTA : IDisposable
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
/*
[Fact] void ENTROPY() {
ENTROPY_Series QL = new(bars.Close, period, useNaN: false);
var pta = df.ta.entropy(close: df.close, length: period);
@@ -309,7 +311,7 @@ public class PandasTA : IDisposable
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
*/
[Fact] void SMA() {
SMA_Series QL = new(bars.Close, period, false);
var pta = df.ta.sma(close: df.close, length: period);
@@ -320,7 +322,7 @@ public class PandasTA : IDisposable
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
/*
[Fact] void SSDEV() {
SSDEV_Series QL = new(bars.Close, period, useNaN: false);
var pta = df.ta.stdev(close: df.close, length: period, ddof: 1);
@@ -432,5 +434,6 @@ public class PandasTA : IDisposable
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
}
*/
}
}
*/