mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-02 11:37:42 +00:00
Minor update
This commit is contained in:
@@ -2,9 +2,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Title>QuanTAlib</Title>
|
||||
<Version>0.2.5</Version>
|
||||
<AssemblyVersion>0.2.5</AssemblyVersion>
|
||||
<FileVersion>0.2.5</FileVersion>
|
||||
<Version>0.2.27</Version>
|
||||
<AssemblyVersion>0.2.27</AssemblyVersion>
|
||||
<FileVersion>0.2.27</FileVersion>
|
||||
<Product>Library of TA Calculations, Charts and Strategies for Quantower</Product>
|
||||
<Description>Quantitative Technical Analysis Library in C# for Quantower</Description>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
@@ -24,7 +24,7 @@
|
||||
<IsPublishable>True</IsPublishable>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
|
||||
<DebugType>embedded</DebugType>
|
||||
<DebugType>full</DebugType>
|
||||
<ProduceReferenceAssembly>True</ProduceReferenceAssembly>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<PackageTags>
|
||||
|
||||
+139
-127
@@ -21,144 +21,156 @@ Issues:
|
||||
|
||||
</summary> */
|
||||
|
||||
public class JMA_Series : TSeries {
|
||||
protected readonly int _period;
|
||||
protected readonly bool _NaN;
|
||||
protected readonly TSeries _data;
|
||||
private readonly System.Collections.Generic.List<double> volty_short = new();
|
||||
private readonly System.Collections.Generic.List<double> vsum_buff = new();
|
||||
private readonly double pr;
|
||||
private double upperBand, lowerBand, vsum, Kv;
|
||||
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 class JMA_Series : TSeries
|
||||
{
|
||||
protected readonly int _period;
|
||||
protected readonly bool _NaN;
|
||||
protected readonly TSeries _data;
|
||||
private readonly System.Collections.Generic.List<double> volty_short = new();
|
||||
private readonly System.Collections.Generic.List<double> vsum_buff = new();
|
||||
private readonly double pr;
|
||||
private double upperBand, lowerBand, vsum, Kv;
|
||||
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;
|
||||
|
||||
//core constructors
|
||||
public JMA_Series(int period, double phase, int vshort, int vlong, bool useNaN) {
|
||||
_period = period;
|
||||
_NaN = useNaN;
|
||||
Name = $"JMA({period})";
|
||||
upperBand = lowerBand = prev_ma1 = prev_det0 = prev_det1 = prev_vsum = prev_jma = Kv = 0.0;
|
||||
pr = (phase * 0.01) + 1.5;
|
||||
if (phase < -100) { pr = 0.5; }
|
||||
if (phase > 100) { pr = 2.5; }
|
||||
_voltyS = vshort;
|
||||
_voltyL = vlong;
|
||||
}
|
||||
//core constructors
|
||||
public JMA_Series(int period, double phase, int vshort, int vlong, bool useNaN)
|
||||
{
|
||||
_period = period;
|
||||
_NaN = useNaN;
|
||||
Name = $"JMA({period})";
|
||||
upperBand = lowerBand = prev_ma1 = prev_det0 = prev_det1 = prev_vsum = prev_jma = Kv = 0.0;
|
||||
pr = (phase * 0.01) + 1.5;
|
||||
if (phase < -100) { pr = 0.5; }
|
||||
if (phase > 100) { pr = 2.5; }
|
||||
_voltyS = vshort;
|
||||
_voltyL = vlong;
|
||||
}
|
||||
|
||||
public JMA_Series(TSeries source, int period, double phase, int vshort, int vlong, bool useNaN) : this(period, phase, vshort, vlong, useNaN) {
|
||||
_data = source;
|
||||
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
|
||||
_data.Pub += Sub;
|
||||
Add(_data);
|
||||
}
|
||||
public JMA_Series() : this(period: 0, phase: 0, vshort:10, vlong:65, useNaN: false) { }
|
||||
public JMA_Series(int period) : this(period: period, phase: 0, vshort: 10, vlong: 65, useNaN: false) { }
|
||||
public JMA_Series(TBars source) : this(source.Close, period:0, phase:0.0, vshort:10, vlong:65, useNaN:false) { }
|
||||
public JMA_Series(TBars source, int period) : this(source.Close, period, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { }
|
||||
public JMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, phase: 0.0, vshort: 10, vlong: 65, useNaN: useNaN) { }
|
||||
public JMA_Series(TSeries source) : this(source, period:0, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { }
|
||||
public JMA_Series(TSeries source, int period) : this(source: source, period: period, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { }
|
||||
public JMA_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, phase: 0.0, vshort: 10, vlong: 65, useNaN: useNaN) { }
|
||||
public JMA_Series(TSeries source, int period, double phase, int vshort, int vlong, bool useNaN) : this(period, phase, vshort, vlong, useNaN)
|
||||
{
|
||||
_data = source;
|
||||
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
|
||||
_data.Pub += Sub;
|
||||
Add(_data);
|
||||
}
|
||||
public JMA_Series() : this(period: 0, phase: 0, vshort: 10, vlong: 65, useNaN: false) { }
|
||||
public JMA_Series(int period) : this(period: period, phase: 0, vshort: 10, vlong: 65, useNaN: false) { }
|
||||
public JMA_Series(TBars source) : this(source.Close, period: 0, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { }
|
||||
public JMA_Series(TBars source, int period) : this(source.Close, period, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { }
|
||||
public JMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, phase: 0.0, vshort: 10, vlong: 65, useNaN: useNaN) { }
|
||||
public JMA_Series(TSeries source) : this(source, period: 0, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { }
|
||||
public JMA_Series(TSeries source, int period) : this(source: source, period: period, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { }
|
||||
public JMA_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, phase: 0.0, vshort: 10, vlong: 65, useNaN: useNaN) { }
|
||||
|
||||
//////////////////
|
||||
// core Add() algo
|
||||
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
|
||||
if (this.Count == 0) { prev_ma1 = prev_jma = TValue.v; }
|
||||
if (update) {
|
||||
upperBand = p_upperBand;
|
||||
lowerBand = p_lowerBand;
|
||||
Kv = p_Kv;
|
||||
prev_vsum = p_prev_vsum;
|
||||
prev_ma1 = p_prev_ma1;
|
||||
prev_det0 = p_prev_det0;
|
||||
prev_det1 = p_prev_det1;
|
||||
prev_jma = p_prev_jma;
|
||||
}
|
||||
else {
|
||||
p_upperBand = upperBand;
|
||||
p_lowerBand = lowerBand;
|
||||
p_Kv = Kv;
|
||||
p_prev_vsum = prev_vsum;
|
||||
p_prev_ma1 = prev_ma1;
|
||||
p_prev_det0 = prev_det0;
|
||||
p_prev_det1 = prev_det1;
|
||||
p_prev_jma = prev_jma;
|
||||
}
|
||||
//////////////////
|
||||
// core Add() algo
|
||||
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false)
|
||||
{
|
||||
if (this.Count == 0) { prev_ma1 = prev_jma = TValue.v; }
|
||||
if (update)
|
||||
{
|
||||
upperBand = p_upperBand;
|
||||
lowerBand = p_lowerBand;
|
||||
Kv = p_Kv;
|
||||
prev_vsum = p_prev_vsum;
|
||||
prev_ma1 = p_prev_ma1;
|
||||
prev_det0 = p_prev_det0;
|
||||
prev_det1 = p_prev_det1;
|
||||
prev_jma = p_prev_jma;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_upperBand = upperBand;
|
||||
p_lowerBand = lowerBand;
|
||||
p_Kv = Kv;
|
||||
p_prev_vsum = prev_vsum;
|
||||
p_prev_ma1 = prev_ma1;
|
||||
p_prev_det0 = prev_det0;
|
||||
p_prev_det1 = prev_det1;
|
||||
p_prev_jma = prev_jma;
|
||||
}
|
||||
|
||||
if (double.IsNaN(TValue.v)) {
|
||||
return base.Add((TValue.t, double.NaN),update);
|
||||
}
|
||||
if (double.IsNaN(TValue.v))
|
||||
{
|
||||
return base.Add((TValue.t, double.NaN), update);
|
||||
}
|
||||
|
||||
// from Tvalue to volty
|
||||
double del1 = TValue.v - upperBand;
|
||||
double del2 = TValue.v - lowerBand;
|
||||
upperBand = (del1 > 0) ? TValue.v : TValue.v - (Kv * del1);
|
||||
lowerBand = (del2 < 0) ? TValue.v : TValue.v - (Kv * del2);
|
||||
double volty = 0;
|
||||
if (Math.Abs(del1) > Math.Abs(del2)) { volty = Math.Abs(del1); }
|
||||
if (Math.Abs(del1) < Math.Abs(del2)) { volty = Math.Abs(del2); }
|
||||
// from Tvalue to volty
|
||||
double del1 = TValue.v - upperBand;
|
||||
double del2 = TValue.v - lowerBand;
|
||||
upperBand = (del1 > 0) ? TValue.v : TValue.v - (Kv * del1);
|
||||
lowerBand = (del2 < 0) ? TValue.v : TValue.v - (Kv * del2);
|
||||
double volty = Math.Abs(del1) > Math.Abs(del2) ? Math.Abs(del1) :
|
||||
(Math.Abs(del1) < Math.Abs(del2) ? Math.Abs(del2) :
|
||||
Math.Abs(0.5 * (del1 + del2)));
|
||||
|
||||
//// from volty to avolty
|
||||
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 > _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 volty to avolty
|
||||
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 > _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(_period)) / Math.Log(2.0)) + 2;
|
||||
if (len1 < 0) { len1 = 0; }
|
||||
/// from avolty to rolty
|
||||
double rvolty = (avolty != 0) ? volty / avolty : 0;
|
||||
double len1 = (Math.Log(Math.Sqrt(_period)) / 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; }
|
||||
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 beta = 0.45 * (_period - 1) / (0.45 * (_period - 1) + 2);
|
||||
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;
|
||||
//// from rvolty to second smoothing
|
||||
double pow2 = Math.Pow(rvolty, pow1);
|
||||
double beta = 0.45 * (_period - 1) / (0.45 * (_period - 1) + 2);
|
||||
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;
|
||||
|
||||
double det0 = (1 - beta) * (TValue.v - ma1) + beta * prev_det0;
|
||||
prev_det0 = det0;
|
||||
double ma2 = ma1 + pr * det0;
|
||||
double det0 = (1 - beta) * (TValue.v - ma1) + beta * prev_det0;
|
||||
prev_det0 = det0;
|
||||
double ma2 = ma1 + pr * det0;
|
||||
|
||||
double det1 = ((1 - alpha) * (1 - alpha) * (ma2 - prev_jma)) + (alpha * alpha * prev_det1);
|
||||
prev_det1 = det1;
|
||||
double jma = prev_jma + det1;
|
||||
prev_jma = jma;
|
||||
|
||||
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : jma);
|
||||
return base.Add(res, update);
|
||||
}
|
||||
double det1 = ((1 - alpha) * (1 - alpha) * (ma2 - prev_jma)) + (alpha * alpha * prev_det1);
|
||||
prev_det1 = det1;
|
||||
double jma = prev_jma + det1;
|
||||
prev_jma = jma;
|
||||
|
||||
public override (DateTime t, double v) Add(TSeries data) {
|
||||
if (data == null) { return (DateTime.Today, Double.NaN); }
|
||||
foreach (var item in data) { Add(item, false); }
|
||||
return _data.Last;
|
||||
}
|
||||
public (DateTime t, double v) Add(bool update) {
|
||||
return this.Add(TValue: _data.Last, update: update);
|
||||
}
|
||||
public (DateTime t, double v) Add() {
|
||||
return Add(TValue: _data.Last, update: false);
|
||||
}
|
||||
private new void Sub(object source, TSeriesEventArgs e) {
|
||||
Add(TValue: _data.Last, update: e.update);
|
||||
}
|
||||
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : jma);
|
||||
return base.Add(res, update);
|
||||
}
|
||||
|
||||
//reset calculation
|
||||
public override void Reset() {
|
||||
upperBand = lowerBand = prev_ma1 = prev_det0 = prev_det1 = prev_vsum = prev_jma = Kv = 0.0;
|
||||
}
|
||||
public override (DateTime t, double v) Add(TSeries data)
|
||||
{
|
||||
if (data == null) { return (DateTime.Today, Double.NaN); }
|
||||
foreach (var item in data) { Add(item, false); }
|
||||
return _data.Last;
|
||||
}
|
||||
public (DateTime t, double v) Add(bool update)
|
||||
{
|
||||
return this.Add(TValue: _data.Last, update: update);
|
||||
}
|
||||
public (DateTime t, double v) Add()
|
||||
{
|
||||
return Add(TValue: _data.Last, update: false);
|
||||
}
|
||||
private new void Sub(object source, TSeriesEventArgs e)
|
||||
{
|
||||
Add(TValue: _data.Last, update: e.update);
|
||||
}
|
||||
|
||||
//reset calculation
|
||||
public override void Reset()
|
||||
{
|
||||
upperBand = lowerBand = prev_ma1 = prev_det0 = prev_det1 = prev_vsum = prev_jma = Kv = 0.0;
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ public class TSeriesEventArgs : EventArgs {
|
||||
public class TSeries : List<(DateTime t, double v)> {
|
||||
public List<DateTime> t => this.Select(item => item.t).ToList();
|
||||
public List<double> v => this.Select(item => item.v).ToList();
|
||||
public (DateTime t, double v) Last => this[this.Count - 1];
|
||||
public (DateTime t, double v) Last => this[^1];
|
||||
public int Length => Count;
|
||||
public string Name { get; set; }
|
||||
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TradingPlatform.BusinessLayer;
|
||||
using QuanTAlib;
|
||||
using System.Drawing;
|
||||
|
||||
namespace SimpleMACross {
|
||||
public class SimpleMACross1 : Strategy, ICurrentAccount, ICurrentSymbol {
|
||||
[InputParameter("Symbol", 0)]
|
||||
public Symbol CurrentSymbol { get; set; }
|
||||
|
||||
[InputParameter("Account", 1)]
|
||||
public Account CurrentAccount { get; set; }
|
||||
|
||||
[InputParameter("Fast MA", 2, minimum: 1, maximum: 100, increment: 1, decimalPlaces: 0)]
|
||||
private int FastMA = 5;
|
||||
|
||||
[InputParameter("Slow MA", 3, minimum: 1, maximum: 100, increment: 1, decimalPlaces: 0)]
|
||||
private int SlowMA = 10;
|
||||
|
||||
[InputParameter("Quantity", 4, 0.1, 99999, 0.1, 2)]
|
||||
private double Quantity = 1.0;
|
||||
|
||||
[InputParameter("Period", 5)]
|
||||
private Period period = Period.MIN1;
|
||||
|
||||
public override string[] MonitoringConnectionsIds => new string[] { this.CurrentSymbol?.ConnectionId, this.CurrentAccount?.ConnectionId };
|
||||
|
||||
private HistoricalData hdm;
|
||||
private DateTime prev_time;
|
||||
private readonly TBars bars = new();
|
||||
|
||||
public SimpleMACross1() {
|
||||
this.Name = "MA Cross strategy 3";
|
||||
this.Description = "Raw strategy without any additional functional";
|
||||
}
|
||||
|
||||
protected override void OnRun() {
|
||||
if (this.CurrentAccount != null && this.CurrentAccount.State == BusinessObjectState.Fake) {this.CurrentAccount = Core.Instance.GetAccount(this.CurrentAccount.CreateInfo());}
|
||||
if (this.CurrentSymbol != null && this.CurrentSymbol.State == BusinessObjectState.Fake) {this.CurrentSymbol = Core.Instance.GetSymbol(this.CurrentSymbol.CreateInfo());}
|
||||
if (this.CurrentSymbol == null || this.CurrentAccount == null || this.CurrentSymbol.ConnectionId != this.CurrentAccount.ConnectionId) {
|
||||
this.Log("Incorrect input parameters... Symbol or Account are not specified or they have different connectionID.", StrategyLoggingLevel.Error);
|
||||
return; }
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
this.hdm = this.CurrentSymbol.GetHistory(Period.MIN1, this.CurrentSymbol.HistoryType, Core.TimeUtils.DateTimeUtcNow.AddDays(-1));
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
|
||||
this.LogInfo($"Symbol: {CurrentSymbol.Name} period: {this.period} :-: {this.CurrentSymbol.HistoryType.ToString()} :-: {this.hdm.Count} bars loaded");
|
||||
this.hdm.HistoryItemUpdated += this.Hdm_HistoryItemUpdated;
|
||||
}
|
||||
|
||||
private void Hdm_HistoryItemUpdated(object sender, HistoryEventArgs e) {
|
||||
this.OnUpdate();
|
||||
}
|
||||
|
||||
private void OnUpdate() {
|
||||
bool update = hdm.Last().TimeLeft - prev_time < this.period.Duration ? true : false;
|
||||
if (!update) {prev_time = hdm.Last().TimeLeft;}
|
||||
|
||||
bars.Add(hdm.Last().TimeLeft, hdm.Last()[PriceType.Open], hdm.Last()[PriceType.High],
|
||||
hdm.Last()[PriceType.Low], hdm.Last()[PriceType.Close], hdm.Last()[PriceType.Volume], update);
|
||||
|
||||
if (!update) {this.LogInfo($"{bars.Close.Last().t} OHLC4:{(double)bars.OHLC4.Last.v}");}
|
||||
|
||||
}
|
||||
|
||||
protected override List<StrategyMetric> OnGetMetrics() {
|
||||
var result = base.OnGetMetrics();
|
||||
|
||||
// An example of adding custom strategy metrics:
|
||||
result.Add("Bars processed", this.bars.Count.ToString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected override void OnStop() {
|
||||
if (this.hdm != null) {
|
||||
this.hdm.HistoryItemUpdated -= this.Hdm_HistoryItemUpdated;
|
||||
this.hdm.Dispose();
|
||||
}
|
||||
|
||||
base.OnStop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
"To use unique insights from EPAM's history, expertise, and innovative spirit we want to recalibrate technology strategies to deliver solutions that are not just innovative, but driven by value creation. We envision a future where every client engagement is delivers integrated value from strategy to optimization, and where our technical thought leadership is a benchmark for the industry, ensuring that EPAM is synonymous with transformative digital engineering."
|
||||
|
||||
Reference in New Issue
Block a user