mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-22 12:38:06 +00:00
sln file
This commit is contained in:
@@ -70,12 +70,13 @@ jobs:
|
|||||||
-p:PackageVersion=${{ github.ref == 'refs/heads/dev' && steps.gitversion.outputs.FullSemVer || steps.gitversion.outputs.MajorMinorPatch }}
|
-p:PackageVersion=${{ github.ref == 'refs/heads/dev' && steps.gitversion.outputs.FullSemVer || steps.gitversion.outputs.MajorMinorPatch }}
|
||||||
dotnet build ./quantower/Averages/Averages.csproj --configuration Release --nologo
|
dotnet build ./quantower/Averages/Averages.csproj --configuration Release --nologo
|
||||||
dotnet build ./quantower/Statistics/Statistics.csproj --configuration Release --nologo
|
dotnet build ./quantower/Statistics/Statistics.csproj --configuration Release --nologo
|
||||||
|
dotnet build ./quantower/Volatility/Volatility.csproj --configuration Release --nologo
|
||||||
dotnet build ./SyntheticVendor/SyntheticVendor.csproj --configuration Release --nologo
|
dotnet build ./SyntheticVendor/SyntheticVendor.csproj --configuration Release --nologo
|
||||||
|
|
||||||
- name: Run tests with coverage
|
- name: Run tests with coverage
|
||||||
if: github.ref == 'refs/heads/dev'
|
if: github.ref == 'refs/heads/dev'
|
||||||
run: |
|
run: |
|
||||||
dotnet test --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:CoverletOutput="./TestResults/"
|
dotnet test ./Tests/Tests.csproj --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:CoverletOutput="./TestResults/"
|
||||||
dotnet-coverage collect "dotnet test" -f xml -o "coverage.xml"
|
dotnet-coverage collect "dotnet test" -f xml -o "coverage.xml"
|
||||||
|
|
||||||
- name: Generate and process coverage report
|
- name: Generate and process coverage report
|
||||||
@@ -105,7 +106,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||||
run: dotnet sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}"
|
run: dotnet sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}"
|
||||||
|
|
||||||
- name: Publish release assets
|
- name: Publish release assets
|
||||||
uses: SourceSprint/upload-multiple-releases@1.0.7
|
uses: SourceSprint/upload-multiple-releases@1.0.7
|
||||||
|
|||||||
+2
-2
@@ -1,10 +1,10 @@
|
|||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 17
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 17.0.31903.59
|
VisualStudioVersion = 17.0.31903.59
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "quantalib", "lib\quantalib.csproj", "{A1B2C3D4-E5F6-47G8-H9I0-J1K2L3M4N5O6}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "quantalib", "lib\quantalib.csproj", "{A1B2C3D4-E5F6-47G8-H9I0-J1K2L3M4N5O6}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "tests\Tests.csproj", "{B2C3D4E5-F6G7-48H9-I0J1-K2L3M4N5O6P7}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{B2C3D4E5-F6G7-48H9-I0J1-K2L3M4N5O6P7}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SyntheticVendor", "SyntheticVendor\SyntheticVendor.csproj", "{C3D4E5F6-G7H8-49I0-J1K2-L3M4N5O6P7Q8}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SyntheticVendor", "SyntheticVendor\SyntheticVendor.csproj", "{C3D4E5F6-G7H8-49I0-J1K2-L3M4N5O6P7Q8}"
|
||||||
EndProject
|
EndProject
|
||||||
|
|||||||
@@ -751,8 +751,10 @@ namespace SyntheticVendorNamespace
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma warning disable S2245
|
||||||
|
// NOSONAR
|
||||||
readonly Random random = new Random();
|
readonly Random random = new Random();
|
||||||
|
#pragma warning restore S2245
|
||||||
private double currentAmplitude = 100;
|
private double currentAmplitude = 100;
|
||||||
private HistoryItemBar GenerateAMSignal(DateTime time, TimeSpan slice)
|
private HistoryItemBar GenerateAMSignal(DateTime time, TimeSpan slice)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ namespace QuanTAlib
|
|||||||
[
|
[
|
||||||
new Ema(period: 10, useSma: true),
|
new Ema(period: 10, useSma: true),
|
||||||
new Alma(period: 14, offset: 0.85, sigma: 6),
|
new Alma(period: 14, offset: 0.85, sigma: 6),
|
||||||
|
new Afirma(periods: 4, taps: 4, window: Afirma.WindowType.Blackman),
|
||||||
new Convolution(new double[] { 1.0, 2, 3, 2, 1 }),
|
new Convolution(new double[] { 1.0, 2, 3, 2, 1 }),
|
||||||
new Dema(period: 14),
|
new Dema(period: 14),
|
||||||
new Dsma(period: 14),
|
new Dsma(period: 14),
|
||||||
|
|||||||
@@ -6,11 +6,6 @@ namespace QuanTAlib;
|
|||||||
/// The weights are decreasing over the period with p^2 decay, and the most recent data has the heaviest weight.
|
/// The weights are decreasing over the period with p^2 decay, and the most recent data has the heaviest weight.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Smoothness: ★★★★★ (5/5)
|
|
||||||
/// Sensitivity: ★★★☆☆ (3/5)
|
|
||||||
/// Overshooting: ★★★★☆ (4/5)
|
|
||||||
/// Lag: ★★☆☆☆ (2/5)
|
|
||||||
///
|
|
||||||
/// The DWMA is calculated by applying two WMAs in sequence:
|
/// The DWMA is calculated by applying two WMAs in sequence:
|
||||||
/// 1. An inner WMA is applied to the input data.
|
/// 1. An inner WMA is applied to the input data.
|
||||||
/// 2. An outer WMA is then applied to the result of the inner WMA.
|
/// 2. An outer WMA is then applied to the result of the inner WMA.
|
||||||
@@ -28,7 +23,6 @@ namespace QuanTAlib;
|
|||||||
|
|
||||||
public class Dwma : AbstractBase
|
public class Dwma : AbstractBase
|
||||||
{
|
{
|
||||||
private readonly int _period;
|
|
||||||
private readonly Wma _innerWma;
|
private readonly Wma _innerWma;
|
||||||
private readonly Wma _outerWma;
|
private readonly Wma _outerWma;
|
||||||
|
|
||||||
@@ -38,11 +32,10 @@ public class Dwma : AbstractBase
|
|||||||
{
|
{
|
||||||
throw new ArgumentException("Period must be greater than or equal to 1.", nameof(period));
|
throw new ArgumentException("Period must be greater than or equal to 1.", nameof(period));
|
||||||
}
|
}
|
||||||
_period = period;
|
|
||||||
_innerWma = new Wma(period);
|
_innerWma = new Wma(period);
|
||||||
_outerWma = new Wma(period);
|
_outerWma = new Wma(period);
|
||||||
Name = "Wma";
|
Name = "Wma";
|
||||||
WarmupPeriod = 2 * _period - 1;
|
WarmupPeriod = 2 * period - 1;
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ namespace QuanTAlib;
|
|||||||
|
|
||||||
public class Fwma : AbstractBase
|
public class Fwma : AbstractBase
|
||||||
{
|
{
|
||||||
private readonly int _period;
|
|
||||||
private readonly Convolution _convolution;
|
private readonly Convolution _convolution;
|
||||||
|
|
||||||
public Fwma(int period)
|
public Fwma(int period)
|
||||||
@@ -11,8 +10,7 @@ public class Fwma : AbstractBase
|
|||||||
{
|
{
|
||||||
throw new ArgumentException("Period must be greater than or equal to 1.", nameof(period));
|
throw new ArgumentException("Period must be greater than or equal to 1.", nameof(period));
|
||||||
}
|
}
|
||||||
_period = period;
|
_convolution = new Convolution(GenerateKernel(period));
|
||||||
_convolution = new Convolution(GenerateKernel(_period));
|
|
||||||
Name = "Fwma";
|
Name = "Fwma";
|
||||||
WarmupPeriod = period;
|
WarmupPeriod = period;
|
||||||
Init();
|
Init();
|
||||||
|
|||||||
+1
-3
@@ -2,7 +2,6 @@ namespace QuanTAlib;
|
|||||||
|
|
||||||
public class Gma : AbstractBase
|
public class Gma : AbstractBase
|
||||||
{
|
{
|
||||||
private readonly int _period;
|
|
||||||
private readonly Convolution _convolution;
|
private readonly Convolution _convolution;
|
||||||
|
|
||||||
public Gma(int period)
|
public Gma(int period)
|
||||||
@@ -11,8 +10,7 @@ public class Gma : AbstractBase
|
|||||||
{
|
{
|
||||||
throw new ArgumentException("Period must be greater than or equal to 1.", nameof(period));
|
throw new ArgumentException("Period must be greater than or equal to 1.", nameof(period));
|
||||||
}
|
}
|
||||||
_period = period;
|
_convolution = new Convolution(GenerateKernel(period));
|
||||||
_convolution = new Convolution(GenerateKernel(_period));
|
|
||||||
Name = "Gma";
|
Name = "Gma";
|
||||||
WarmupPeriod = period;
|
WarmupPeriod = period;
|
||||||
Init();
|
Init();
|
||||||
|
|||||||
+2
-4
@@ -2,7 +2,6 @@ namespace QuanTAlib;
|
|||||||
|
|
||||||
public class Hma : AbstractBase
|
public class Hma : AbstractBase
|
||||||
{
|
{
|
||||||
private readonly int _period, _sqrtPeriod;
|
|
||||||
private readonly Convolution _wmaHalf, _wmaFull, _wmaFinal;
|
private readonly Convolution _wmaHalf, _wmaFull, _wmaFinal;
|
||||||
|
|
||||||
public Hma(int period)
|
public Hma(int period)
|
||||||
@@ -11,13 +10,12 @@ public class Hma : AbstractBase
|
|||||||
{
|
{
|
||||||
throw new ArgumentException("Period must be greater than or equal to 2.", nameof(period));
|
throw new ArgumentException("Period must be greater than or equal to 2.", nameof(period));
|
||||||
}
|
}
|
||||||
_period = period;
|
int _sqrtPeriod = (int)Math.Sqrt(period);
|
||||||
_sqrtPeriod = (int)Math.Sqrt(period);
|
|
||||||
_wmaHalf = new Convolution(GenerateWmaKernel(period / 2));
|
_wmaHalf = new Convolution(GenerateWmaKernel(period / 2));
|
||||||
_wmaFull = new Convolution(GenerateWmaKernel(period));
|
_wmaFull = new Convolution(GenerateWmaKernel(period));
|
||||||
_wmaFinal = new Convolution(GenerateWmaKernel(_sqrtPeriod));
|
_wmaFinal = new Convolution(GenerateWmaKernel(_sqrtPeriod));
|
||||||
Name = "Hma";
|
Name = "Hma";
|
||||||
WarmupPeriod = _period + _sqrtPeriod - 1;
|
WarmupPeriod = period + _sqrtPeriod - 1;
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ namespace QuanTAlib;
|
|||||||
|
|
||||||
public class Sinema : AbstractBase
|
public class Sinema : AbstractBase
|
||||||
{
|
{
|
||||||
private readonly int _period;
|
|
||||||
private readonly Convolution _convolution;
|
private readonly Convolution _convolution;
|
||||||
|
|
||||||
public Sinema(int period)
|
public Sinema(int period)
|
||||||
@@ -11,8 +10,7 @@ public class Sinema : AbstractBase
|
|||||||
{
|
{
|
||||||
throw new ArgumentException("Period must be greater than or equal to 1.", nameof(period));
|
throw new ArgumentException("Period must be greater than or equal to 1.", nameof(period));
|
||||||
}
|
}
|
||||||
_period = period;
|
_convolution = new Convolution(GenerateKernel(period));
|
||||||
_convolution = new Convolution(GenerateKernel(_period));
|
|
||||||
Name = "Sinema";
|
Name = "Sinema";
|
||||||
WarmupPeriod = period;
|
WarmupPeriod = period;
|
||||||
Init();
|
Init();
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ public class Sma : AbstractBase
|
|||||||
{
|
{
|
||||||
// inherited _index
|
// inherited _index
|
||||||
// inherited _value
|
// inherited _value
|
||||||
private readonly int Period;
|
|
||||||
private readonly CircularBuffer _buffer;
|
private readonly CircularBuffer _buffer;
|
||||||
|
|
||||||
public Sma(int period)
|
public Sma(int period)
|
||||||
@@ -13,7 +12,6 @@ public class Sma : AbstractBase
|
|||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
|
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
|
||||||
}
|
}
|
||||||
Period = period;
|
|
||||||
WarmupPeriod = period;
|
WarmupPeriod = period;
|
||||||
_buffer = new CircularBuffer(period);
|
_buffer = new CircularBuffer(period);
|
||||||
Name = "Sma";
|
Name = "Sma";
|
||||||
@@ -28,11 +26,6 @@ public class Sma : AbstractBase
|
|||||||
}
|
}
|
||||||
//inhereted public void Sub(object source, in ValueEventArgs args)
|
//inhereted public void Sub(object source, in ValueEventArgs args)
|
||||||
|
|
||||||
public override void Init()
|
|
||||||
{
|
|
||||||
base.Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void ManageState(bool isNew)
|
protected override void ManageState(bool isNew)
|
||||||
{
|
{
|
||||||
if (isNew)
|
if (isNew)
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ namespace QuanTAlib;
|
|||||||
|
|
||||||
public class Trima : AbstractBase
|
public class Trima : AbstractBase
|
||||||
{
|
{
|
||||||
private readonly int _period;
|
|
||||||
private readonly Convolution _convolution;
|
private readonly Convolution _convolution;
|
||||||
|
|
||||||
public Trima(int period)
|
public Trima(int period)
|
||||||
@@ -11,8 +10,7 @@ public class Trima : AbstractBase
|
|||||||
{
|
{
|
||||||
throw new ArgumentException("Period must be greater than or equal to 1.", nameof(period));
|
throw new ArgumentException("Period must be greater than or equal to 1.", nameof(period));
|
||||||
}
|
}
|
||||||
_period = period;
|
_convolution = new Convolution(GenerateKernel(period));
|
||||||
_convolution = new Convolution(GenerateKernel(_period));
|
|
||||||
Name = "Trima";
|
Name = "Trima";
|
||||||
WarmupPeriod = period;
|
WarmupPeriod = period;
|
||||||
Init();
|
Init();
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ namespace QuanTAlib;
|
|||||||
|
|
||||||
public class Vidya : AbstractBase
|
public class Vidya : AbstractBase
|
||||||
{
|
{
|
||||||
private readonly int _shortPeriod;
|
|
||||||
private readonly int _longPeriod;
|
private readonly int _longPeriod;
|
||||||
private readonly double _alpha;
|
private readonly double _alpha;
|
||||||
private double _lastVIDYA, _p_lastVIDYA;
|
private double _lastVIDYA, _p_lastVIDYA;
|
||||||
@@ -19,12 +18,11 @@ public class Vidya : AbstractBase
|
|||||||
{
|
{
|
||||||
throw new ArgumentException("Short period must be greater than or equal to 1.", nameof(shortPeriod));
|
throw new ArgumentException("Short period must be greater than or equal to 1.", nameof(shortPeriod));
|
||||||
}
|
}
|
||||||
_shortPeriod = shortPeriod;
|
|
||||||
_longPeriod = (longPeriod == 0) ? shortPeriod * 4 : longPeriod;
|
_longPeriod = (longPeriod == 0) ? shortPeriod * 4 : longPeriod;
|
||||||
_alpha = alpha;
|
_alpha = alpha;
|
||||||
WarmupPeriod = _longPeriod;
|
WarmupPeriod = _longPeriod;
|
||||||
Name = $"Vidya({_shortPeriod},{_longPeriod})";
|
Name = $"Vidya({shortPeriod},{_longPeriod})";
|
||||||
_shortBuffer = new CircularBuffer(_shortPeriod);
|
_shortBuffer = new CircularBuffer(shortPeriod);
|
||||||
_longBuffer = new CircularBuffer(_longPeriod);
|
_longBuffer = new CircularBuffer(_longPeriod);
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-11
@@ -30,15 +30,11 @@ public readonly record struct TBar(DateTime Time, double Open, double High, doub
|
|||||||
|
|
||||||
public TBar() : this(DateTime.UtcNow, 0, 0, 0, 0, 0) { }
|
public TBar() : this(DateTime.UtcNow, 0, 0, 0, 0, 0) { }
|
||||||
public TBar(double Open, double High, double Low, double Close, double Volume, bool IsNew = true) : this(DateTime.UtcNow, Open, High, Low, Close, Volume, IsNew) { }
|
public TBar(double Open, double High, double Low, double Close, double Volume, bool IsNew = true) : this(DateTime.UtcNow, Open, High, Low, Close, Volume, IsNew) { }
|
||||||
|
|
||||||
// when TBar casts to double, it returns its Close
|
|
||||||
public static implicit operator double(TBar bar) => bar.Close;
|
|
||||||
public static implicit operator DateTime(TBar tv) => tv.Time;
|
|
||||||
|
|
||||||
// castings for sloppy people - a single double injected into a TBar, and a single TValue injected into a TBar
|
|
||||||
public TBar(double value) : this(Time: DateTime.UtcNow, Open: value, High: value, Low: value, Close: value, Volume: value, IsNew: true) { }
|
public TBar(double value) : this(Time: DateTime.UtcNow, Open: value, High: value, Low: value, Close: value, Volume: value, IsNew: true) { }
|
||||||
public TBar(TValue value) : this(Time: value.Time, Open: value.Value, High: value.Value, Low: value.Value, Close: value.Value, Volume: value.Value, IsNew: value.IsNew) { }
|
public TBar(TValue value) : this(Time: value.Time, Open: value.Value, High: value.Value, Low: value.Value, Close: value.Value, Volume: value.Value, IsNew: value.IsNew) { }
|
||||||
|
|
||||||
|
public static implicit operator double(TBar bar) => bar.Close;
|
||||||
|
public static implicit operator DateTime(TBar tv) => tv.Time;
|
||||||
public override string ToString() => $"[{Time:yyyy-MM-dd HH:mm:ss}: O={Open:F2}, H={High:F2}, L={Low:F2}, C={Close:F2}, V={Volume:F2}]";
|
public override string ToString() => $"[{Time:yyyy-MM-dd HH:mm:ss}: O={Open:F2}, H={High:F2}, L={Low:F2}, C={Close:F2}, V={Volume:F2}]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,11 +66,8 @@ public class TBarSeries : List<TBar>
|
|||||||
public TBarSeries()
|
public TBarSeries()
|
||||||
{
|
{
|
||||||
this.Name = "Bar";
|
this.Name = "Bar";
|
||||||
Open = new();
|
(Open, High, Low, Close, Volume) = ([], [], [], [], []);
|
||||||
High = new();
|
|
||||||
Low = new();
|
|
||||||
Close = new();
|
|
||||||
Volume = new();
|
|
||||||
}
|
}
|
||||||
public TBarSeries(object source) : this()
|
public TBarSeries(object source) : this()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -27,11 +27,6 @@ namespace QuanTAlib
|
|||||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Init()
|
|
||||||
{
|
|
||||||
base.Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void ManageState(bool isNew)
|
protected override void ManageState(bool isNew)
|
||||||
{
|
{
|
||||||
if (isNew)
|
if (isNew)
|
||||||
|
|||||||
@@ -24,11 +24,6 @@ public class Mode : AbstractBase
|
|||||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Init()
|
|
||||||
{
|
|
||||||
base.Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void ManageState(bool isNew)
|
protected override void ManageState(bool isNew)
|
||||||
{
|
{
|
||||||
if (isNew)
|
if (isNew)
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ namespace QuanTAlib;
|
|||||||
|
|
||||||
public class Atr : AbstractBarBase
|
public class Atr : AbstractBarBase
|
||||||
{
|
{
|
||||||
private readonly int _period;
|
|
||||||
private readonly Ema _ma;
|
private readonly Ema _ma;
|
||||||
private double _prevClose, _p_prevClose;
|
private double _prevClose, _p_prevClose;
|
||||||
|
|
||||||
@@ -12,10 +11,9 @@ public class Atr : AbstractBarBase
|
|||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
|
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
|
||||||
}
|
}
|
||||||
_period = period;
|
|
||||||
_ma = new(1.0/period);
|
_ma = new(1.0/period);
|
||||||
WarmupPeriod = _ma.WarmupPeriod;
|
WarmupPeriod = _ma.WarmupPeriod;
|
||||||
Name = $"ATR({_period})";
|
Name = $"ATR({period})";
|
||||||
}
|
}
|
||||||
|
|
||||||
public Atr(object source, int period) : this(period)
|
public Atr(object source, int period) : this(period)
|
||||||
|
|||||||
@@ -18,6 +18,9 @@
|
|||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="..\*.cs">
|
||||||
|
<Link>%(Filename)%(Extension)</Link>
|
||||||
|
</Compile>
|
||||||
<Reference Include="TradingPlatform.BusinessLayer">
|
<Reference Include="TradingPlatform.BusinessLayer">
|
||||||
<HintPath>..\..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
|
<HintPath>..\..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
|||||||
@@ -18,6 +18,9 @@
|
|||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="..\*.cs">
|
||||||
|
<Link>%(Filename)%(Extension)</Link>
|
||||||
|
</Compile>
|
||||||
<Reference Include="TradingPlatform.BusinessLayer">
|
<Reference Include="TradingPlatform.BusinessLayer">
|
||||||
<HintPath>..\..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
|
<HintPath>..\..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
|||||||
@@ -1,187 +0,0 @@
|
|||||||
using System.Drawing;
|
|
||||||
using TradingPlatform.BusinessLayer;
|
|
||||||
using TradingPlatform.BusinessLayer.Chart;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Drawing.Drawing2D;
|
|
||||||
using System.Collections;
|
|
||||||
using TradingPlatform.BusinessLayer.TimeSync;
|
|
||||||
|
|
||||||
namespace QuanTAlib;
|
|
||||||
|
|
||||||
#pragma warning disable CA1416 // Validate platform compatibility
|
|
||||||
public abstract class IndicatorBase : Indicator, IWatchlistIndicator
|
|
||||||
{
|
|
||||||
|
|
||||||
[InputParameter("Data source", sortIndex: 17, variants: [
|
|
||||||
"Open", 1,
|
|
||||||
"High", 2,
|
|
||||||
"Low", 3,
|
|
||||||
"Close", 4,
|
|
||||||
"HL/2 (Median)", 5,
|
|
||||||
"OC/2 (Midpoint)", 6,
|
|
||||||
"OHL/3 (Mean)", 7,
|
|
||||||
"HLC/3 (Typical)", 8,
|
|
||||||
"OHLC/4 (Average)", 9,
|
|
||||||
"HLCC/4 (Weighted)", 10
|
|
||||||
])]
|
|
||||||
public int Source { get; set; } = 4;
|
|
||||||
|
|
||||||
[InputParameter("Show cold values", sortIndex: 20)]
|
|
||||||
public bool ShowColdValues { get; set; } = true;
|
|
||||||
public int MinHistoryDepths { get; set; }
|
|
||||||
|
|
||||||
// LineSeries.LineSeries(string, Color, int, LineStyle)'
|
|
||||||
|
|
||||||
protected LineSeries? Series;
|
|
||||||
protected string SourceName;
|
|
||||||
protected abstract AbstractBase QuanTAlib { get; }
|
|
||||||
|
|
||||||
int IWatchlistIndicator.MinHistoryDepths => 0;
|
|
||||||
|
|
||||||
protected IndicatorBase()
|
|
||||||
{
|
|
||||||
OnBackGround = true;
|
|
||||||
SeparateWindow = false;
|
|
||||||
SourceName = GetName(Source);
|
|
||||||
Series = new(name: $"{Name}", color: Color.RoyalBlue, width: 2, style: LineStyle.Solid);
|
|
||||||
|
|
||||||
AddLineSeries(Series);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void InitIndicator();
|
|
||||||
|
|
||||||
protected override void OnInit()
|
|
||||||
{
|
|
||||||
InitIndicator();
|
|
||||||
SourceName = GetName(Source);
|
|
||||||
base.OnInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnUpdate(UpdateArgs args)
|
|
||||||
{
|
|
||||||
TBar bar = new(Time: Time(),
|
|
||||||
Open: GetPrice(PriceType.Open),
|
|
||||||
High: GetPrice(PriceType.High),
|
|
||||||
Low: GetPrice(PriceType.Low),
|
|
||||||
Close: GetPrice(PriceType.Close),
|
|
||||||
Volume: GetPrice(PriceType.Volume),
|
|
||||||
IsNew: args.Reason == UpdateReason.NewBar || args.Reason == UpdateReason.HistoricalBar);
|
|
||||||
|
|
||||||
double price = Source switch
|
|
||||||
{
|
|
||||||
1 => bar.Open,
|
|
||||||
2 => bar.High,
|
|
||||||
3 => bar.Low,
|
|
||||||
4 => bar.Close,
|
|
||||||
5 => bar.HL2,
|
|
||||||
6 => bar.OC2,
|
|
||||||
7 => bar.OHL3,
|
|
||||||
8 => bar.HLC3,
|
|
||||||
9 => bar.OHLC4,
|
|
||||||
10 => bar.HLCC4,
|
|
||||||
_ => bar.Close
|
|
||||||
};
|
|
||||||
|
|
||||||
TValue input = new TValue(bar.Time, price, bar.IsNew);
|
|
||||||
TValue result = QuanTAlib.Calc(input);
|
|
||||||
Series!.SetValue(result.Value);
|
|
||||||
Series!.SetMarker(0, Color.Transparent);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnPaintChart(PaintChartEventArgs args)
|
|
||||||
{
|
|
||||||
base.OnPaintChart(args);
|
|
||||||
List<Point> allPoints = new List<Point>();
|
|
||||||
if (CurrentChart == null) { return; }
|
|
||||||
|
|
||||||
Graphics gr = args.Graphics;
|
|
||||||
|
|
||||||
var mainWindow = this.CurrentChart.Windows[args.WindowIndex];
|
|
||||||
var converter = mainWindow.CoordinatesConverter;
|
|
||||||
var clientRect = mainWindow.ClientRectangle;
|
|
||||||
|
|
||||||
gr.SetClip(clientRect);
|
|
||||||
DateTime leftTime = new[] { converter.GetTime(clientRect.Left), Time(this.Count - 1) }.Max();
|
|
||||||
DateTime rightTime = new[] { converter.GetTime(clientRect.Right), Time(0) }.Min();
|
|
||||||
|
|
||||||
int leftIndex = (int)HistoricalData.GetIndexByTime(leftTime.Ticks) + 1;
|
|
||||||
int rightIndex = (int)HistoricalData.GetIndexByTime(rightTime.Ticks);
|
|
||||||
|
|
||||||
for (int i = rightIndex; i < leftIndex; i++)
|
|
||||||
{
|
|
||||||
int barX = (int)converter.GetChartX(Time(i));
|
|
||||||
int barY = (int)converter.GetChartY(Series![i]);
|
|
||||||
int halfBarWidth = CurrentChart.BarsWidth / 2;
|
|
||||||
Point point = new Point(barX + halfBarWidth, barY);
|
|
||||||
allPoints.Add(point);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allPoints.Count > 1)
|
|
||||||
{
|
|
||||||
DrawSmoothCombinedCurve(gr, allPoints, this.Count - QuanTAlib.WarmupPeriod - rightIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawSmoothCombinedCurve(Graphics gr, List<Point> allPoints, int hotCount)
|
|
||||||
{
|
|
||||||
if (allPoints.Count < 2) { return; }
|
|
||||||
|
|
||||||
using (Pen defaultPen = new(Series!.Color, Series.Width) { DashStyle = ConvertLineStyleToDashStyle(Series.Style) })
|
|
||||||
using (Pen coldPen = new(Series!.Color, Series.Width) { DashStyle = DashStyle.Dot })
|
|
||||||
{
|
|
||||||
// Draw the hot part
|
|
||||||
if (hotCount > 0)
|
|
||||||
{
|
|
||||||
var hotPoints = allPoints.Take(Math.Min(hotCount + 1, allPoints.Count)).ToArray();
|
|
||||||
gr.DrawCurve(defaultPen, hotPoints, 0, hotPoints.Length - 1, (float)0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw the cold part
|
|
||||||
if (ShowColdValues && hotCount < allPoints.Count)
|
|
||||||
{
|
|
||||||
var coldPoints = allPoints.Skip(Math.Max(0, hotCount)).ToArray();
|
|
||||||
gr.DrawCurve(coldPen, coldPoints, 0, coldPoints.Length - 1, (float)0.1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private static DashStyle ConvertLineStyleToDashStyle(LineStyle lineStyle)
|
|
||||||
{
|
|
||||||
return lineStyle switch
|
|
||||||
{
|
|
||||||
LineStyle.Solid => DashStyle.Solid,
|
|
||||||
LineStyle.Dash => DashStyle.Dash,
|
|
||||||
LineStyle.Dot => DashStyle.Dot,
|
|
||||||
LineStyle.DashDot => DashStyle.DashDot,
|
|
||||||
_ => DashStyle.Solid,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
protected static void DrawText(Graphics gr, string text, Rectangle clientRect)
|
|
||||||
{
|
|
||||||
Font font = new Font("Inter", 8);
|
|
||||||
SizeF textSize = gr.MeasureString(text, font);
|
|
||||||
RectangleF textRect = new RectangleF(clientRect.Left + 5,
|
|
||||||
clientRect.Bottom - textSize.Height - 10,
|
|
||||||
textSize.Width + 10, textSize.Height + 10);
|
|
||||||
gr.FillRectangle(SystemBrushes.ControlDarkDark, textRect);
|
|
||||||
gr.DrawString(text, font, Brushes.White, new PointF(textRect.X + 6, textRect.Y + 5));
|
|
||||||
}
|
|
||||||
protected static string GetName(int pType)
|
|
||||||
{
|
|
||||||
return pType switch
|
|
||||||
{
|
|
||||||
1 => "Open",
|
|
||||||
2 => "High",
|
|
||||||
3 => "Low",
|
|
||||||
4 => "Close",
|
|
||||||
5 => "Median",
|
|
||||||
6 => "Midpoint",
|
|
||||||
7 => "Mean",
|
|
||||||
8 => "Typical",
|
|
||||||
9 => "Average",
|
|
||||||
10 => "Weighted",
|
|
||||||
_ => "N/A"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -18,6 +18,9 @@
|
|||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="..\*.cs">
|
||||||
|
<Link>%(Filename)%(Extension)</Link>
|
||||||
|
</Compile>
|
||||||
<Reference Include="TradingPlatform.BusinessLayer">
|
<Reference Include="TradingPlatform.BusinessLayer">
|
||||||
<HintPath>..\..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
|
<HintPath>..\..\.github\TradingPlatform.BusinessLayer.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
|||||||
@@ -1,136 +0,0 @@
|
|||||||
using System.Drawing;
|
|
||||||
using TradingPlatform.BusinessLayer;
|
|
||||||
using TradingPlatform.BusinessLayer.Chart;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Drawing.Drawing2D;
|
|
||||||
using System.Collections;
|
|
||||||
using TradingPlatform.BusinessLayer.TimeSync;
|
|
||||||
|
|
||||||
namespace QuanTAlib;
|
|
||||||
|
|
||||||
#pragma warning disable CA1416 // Validate platform compatibility
|
|
||||||
public abstract class IndicatorBarBase : Indicator, IWatchlistIndicator
|
|
||||||
{
|
|
||||||
|
|
||||||
[InputParameter("Show cold values", sortIndex: 20)]
|
|
||||||
public bool ShowColdValues { get; set; } = true;
|
|
||||||
public int MinHistoryDepths { get; set; }
|
|
||||||
|
|
||||||
// LineSeries.LineSeries(string, Color, int, LineStyle)'
|
|
||||||
|
|
||||||
protected LineSeries? Series;
|
|
||||||
protected abstract AbstractBarBase QuanTAlib { get; }
|
|
||||||
|
|
||||||
int IWatchlistIndicator.MinHistoryDepths => 0;
|
|
||||||
|
|
||||||
protected IndicatorBarBase()
|
|
||||||
{
|
|
||||||
OnBackGround = true;
|
|
||||||
SeparateWindow = false;
|
|
||||||
Series = new(name: $"{Name}", color: Color.RoyalBlue, width: 2, style: LineStyle.Solid);
|
|
||||||
|
|
||||||
AddLineSeries(Series);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void InitIndicator();
|
|
||||||
|
|
||||||
protected override void OnInit()
|
|
||||||
{
|
|
||||||
InitIndicator();
|
|
||||||
base.OnInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnUpdate(UpdateArgs args)
|
|
||||||
{
|
|
||||||
TBar bar = new(Time: Time(),
|
|
||||||
Open: GetPrice(PriceType.Open),
|
|
||||||
High: GetPrice(PriceType.High),
|
|
||||||
Low: GetPrice(PriceType.Low),
|
|
||||||
Close: GetPrice(PriceType.Close),
|
|
||||||
Volume: GetPrice(PriceType.Volume),
|
|
||||||
IsNew: args.Reason == UpdateReason.NewBar || args.Reason == UpdateReason.HistoricalBar);
|
|
||||||
|
|
||||||
TValue result = QuanTAlib.Calc(bar);
|
|
||||||
Series!.SetValue(result.Value);
|
|
||||||
Series!.SetMarker(0, Color.Transparent);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnPaintChart(PaintChartEventArgs args)
|
|
||||||
{
|
|
||||||
base.OnPaintChart(args);
|
|
||||||
List<Point> allPoints = new List<Point>();
|
|
||||||
if (CurrentChart == null) { return; }
|
|
||||||
|
|
||||||
Graphics gr = args.Graphics;
|
|
||||||
|
|
||||||
var mainWindow = this.CurrentChart.Windows[args.WindowIndex];
|
|
||||||
var converter = mainWindow.CoordinatesConverter;
|
|
||||||
var clientRect = mainWindow.ClientRectangle;
|
|
||||||
|
|
||||||
gr.SetClip(clientRect);
|
|
||||||
DateTime leftTime = new[] { converter.GetTime(clientRect.Left), Time(this.Count - 1) }.Max();
|
|
||||||
DateTime rightTime = new[] { converter.GetTime(clientRect.Right), Time(0) }.Min();
|
|
||||||
|
|
||||||
int leftIndex = (int)HistoricalData.GetIndexByTime(leftTime.Ticks) + 1;
|
|
||||||
int rightIndex = (int)HistoricalData.GetIndexByTime(rightTime.Ticks);
|
|
||||||
|
|
||||||
for (int i = rightIndex; i < leftIndex; i++)
|
|
||||||
{
|
|
||||||
int barX = (int)converter.GetChartX(Time(i));
|
|
||||||
int barY = (int)converter.GetChartY(Series![i]);
|
|
||||||
int halfBarWidth = CurrentChart.BarsWidth / 2;
|
|
||||||
Point point = new Point(barX + halfBarWidth, barY);
|
|
||||||
allPoints.Add(point);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allPoints.Count > 1)
|
|
||||||
{
|
|
||||||
DrawSmoothCombinedCurve(gr, allPoints, this.Count - QuanTAlib.WarmupPeriod - rightIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawSmoothCombinedCurve(Graphics gr, List<Point> allPoints, int hotCount)
|
|
||||||
{
|
|
||||||
if (allPoints.Count < 2) { return; }
|
|
||||||
|
|
||||||
using (Pen defaultPen = new(Series!.Color, Series.Width) { DashStyle = ConvertLineStyleToDashStyle(Series.Style) })
|
|
||||||
using (Pen coldPen = new(Series!.Color, Series.Width) { DashStyle = DashStyle.Dot })
|
|
||||||
{
|
|
||||||
// Draw the hot part
|
|
||||||
if (hotCount > 0)
|
|
||||||
{
|
|
||||||
var hotPoints = allPoints.Take(Math.Min(hotCount + 1, allPoints.Count)).ToArray();
|
|
||||||
gr.DrawCurve(defaultPen, hotPoints, 0, hotPoints.Length - 1, (float)0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw the cold part
|
|
||||||
if (ShowColdValues && hotCount < allPoints.Count)
|
|
||||||
{
|
|
||||||
var coldPoints = allPoints.Skip(Math.Max(0, hotCount)).ToArray();
|
|
||||||
gr.DrawCurve(coldPen, coldPoints, 0, coldPoints.Length - 1, (float)0.1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private static DashStyle ConvertLineStyleToDashStyle(LineStyle lineStyle)
|
|
||||||
{
|
|
||||||
return lineStyle switch
|
|
||||||
{
|
|
||||||
LineStyle.Solid => DashStyle.Solid,
|
|
||||||
LineStyle.Dash => DashStyle.Dash,
|
|
||||||
LineStyle.Dot => DashStyle.Dot,
|
|
||||||
LineStyle.DashDot => DashStyle.DashDot,
|
|
||||||
_ => DashStyle.Solid,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
protected static void DrawText(Graphics gr, string text, Rectangle clientRect)
|
|
||||||
{
|
|
||||||
Font font = new Font("Inter", 8);
|
|
||||||
SizeF textSize = gr.MeasureString(text, font);
|
|
||||||
RectangleF textRect = new RectangleF(clientRect.Left + 5,
|
|
||||||
clientRect.Bottom - textSize.Height - 10,
|
|
||||||
textSize.Width + 10, textSize.Height + 10);
|
|
||||||
gr.FillRectangle(SystemBrushes.ControlDarkDark, textRect);
|
|
||||||
gr.DrawString(text, font, Brushes.White, new PointF(textRect.X + 6, textRect.Y + 5));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user