diff --git a/.github/TradingPlatform.BusinessLayer.dll b/.github/TradingPlatform.BusinessLayer.dll
index 0a324bcb..d1cca1dc 100644
Binary files a/.github/TradingPlatform.BusinessLayer.dll and b/.github/TradingPlatform.BusinessLayer.dll differ
diff --git a/.github/TradingPlatform.BusinessLayer.xml b/.github/TradingPlatform.BusinessLayer.xml
index 47ebf0f0..60fa288b 100644
--- a/.github/TradingPlatform.BusinessLayer.xml
+++ b/.github/TradingPlatform.BusinessLayer.xml
@@ -377,21 +377,6 @@
Mediates a history meta data with available data types and intervals on vendor side
-
-
- History data types
-
-
-
-
- History intervals
-
-
-
-
- History intervals
-
-
Asset id bearer
@@ -1948,7 +1933,7 @@
-
+
Gets historical data according to aggregation and other parameters
@@ -2965,21 +2950,11 @@
Gets HistoricalData symbol
-
-
- Gets HistoricalData Period
-
-
Gets HistoricalData aggregation
-
-
- Gets HistoricalData history type
-
-
Gets HistoricalData left time boundary
diff --git a/.github/workflows/Publish.yml b/.github/workflows/Publish.yml
index ada29549..edd100b9 100644
--- a/.github/workflows/Publish.yml
+++ b/.github/workflows/Publish.yml
@@ -43,15 +43,28 @@ jobs:
- name: SonarCloud Scanner Start
env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: |
+ if [[ ${{ github.event_name }} == 'pull_request' ]]; then
+ PR_PARAMS="/d:sonar.pullrequest.key=${{ github.event.pull_request.number }} \
+ /d:sonar.pullrequest.branch=${{ github.head_ref }} \
+ /d:sonar.pullrequest.base=${{ github.base_ref }}"
+ elif [[ ${{ github.event_name }} == 'push' ]]; then
+ BRANCH_PARAMS="/d:sonar.branch.name=${{ github.ref_name }}"
+ else
+ BRANCH_PARAMS="/d:sonar.branch.name=${{ github.ref_name }}"
+ fi
+
dotnet sonarscanner begin \
/k:"mihakralj_QuanTAlib" \
/o:"mihakralj" \
/d:sonar.token="${{ secrets.SONAR_TOKEN }}" \
/d:sonar.host.url="https://sonarcloud.io" \
/d:sonar.cs.dotcover.reportsPaths=dotcover* \
- /d:sonar.scanner.scanAll=false
+ /d:sonar.scanner.scanAll=false \
+ /d:sonar.scm.provider=git \
+ $PR_PARAMS $BRANCH_PARAMS
- name: Build
run: |
@@ -216,7 +229,10 @@ jobs:
build_publish:
needs: [SonarCloud, Code_Coverage, CodeQL, Codacy_Scan, SecurityCodeScan]
- if: success()
+ if: |
+ success() &&
+ (github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev')) ||
+ github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
diff --git a/QuanTAlib.sln b/QuanTAlib.sln
index bd69454d..068fcd79 100644
--- a/QuanTAlib.sln
+++ b/QuanTAlib.sln
@@ -1,5 +1,4 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
+Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
@@ -7,15 +6,15 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "quantalib", "lib\quantalib.
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "quantower", "quantower", "{1B9AC248-76F8-44DD-958D-F1DC08EE1E87}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Statistics", "quantower\Statistics\Statistics.csproj", "{2E9427C7-144F-488E-A29D-789ACC1C32AE}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Statistics", "quantower\Statistics\_Statistics.csproj", "{2E9427C7-144F-488E-A29D-789ACC1C32AE}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Averages", "quantower\Averages\Averages.csproj", "{6BE10C39-4127-446C-818B-7976FCDD51D5}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Averages", "quantower\Averages\_Averages.csproj", "{6BE10C39-4127-446C-818B-7976FCDD51D5}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volatility", "quantower\Volatility\Volatility.csproj", "{B7DC44F7-D3A3-4C70-9025-513E0182B646}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volatility", "quantower\Volatility\_Volatility.csproj", "{B7DC44F7-D3A3-4C70-9025-513E0182B646}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SyntheticVendor", "SyntheticVendor\SyntheticVendor.csproj", "{1CF111D9-33E6-4A11-8FEC-F23300A78D15}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{E204F173-5840-4AA3-BED1-98C8D2F813E3}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{2D97C971-20BF-40DB-94AA-3279F787D3CB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -41,15 +40,16 @@ Global
{B7DC44F7-D3A3-4C70-9025-513E0182B646}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B7DC44F7-D3A3-4C70-9025-513E0182B646}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B7DC44F7-D3A3-4C70-9025-513E0182B646}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {B7DC44F7-D3A3-4C70-9025-513E0182B646}.Release|Any CPU.Build.0 = Release|Any CPU
- {1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Release|Any CPU.Build.0 = Release|Any CPU
- {E204F173-5840-4AA3-BED1-98C8D2F813E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {E204F173-5840-4AA3-BED1-98C8D2F813E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {E204F173-5840-4AA3-BED1-98C8D2F813E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {E204F173-5840-4AA3-BED1-98C8D2F813E3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B7DC44F7-D3A3-4C70-9025-513E0182B646}.Release | Any CPU.ActiveCfg = Release | Any CPU
+ {B7DC44F7-D3A3-4C70-9025-513E0182B646}.Release | Any CPU.Build.0 = Release | Any CPU
+ {1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Debug | Any CPU.ActiveCfg = Debug | Any CPU
+ {1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Debug | Any CPU.Build.0 = Debug | Any CPU
+ {1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Release | Any CPU.ActiveCfg = Release | Any CPU
+ {1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Release | Any CPU.Build.0 = Release | Any CPU
+ {2D97C971-20BF-40DB-94AA-3279F787D3CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2D97C971-20BF-40DB-94AA-3279F787D3CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2D97C971-20BF-40DB-94AA-3279F787D3CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2D97C971-20BF-40DB-94AA-3279F787D3CB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{2E9427C7-144F-488E-A29D-789ACC1C32AE} = {1B9AC248-76F8-44DD-958D-F1DC08EE1E87}
diff --git a/SyntheticVendor/SyntheticVendor.cs b/SyntheticVendor/SyntheticVendor.cs
index 60c2118a..913041a4 100644
--- a/SyntheticVendor/SyntheticVendor.cs
+++ b/SyntheticVendor/SyntheticVendor.cs
@@ -5,10 +5,7 @@ using TradingPlatform.BusinessLayer;
using TradingPlatform.BusinessLayer.Integration;
using System.Diagnostics.CodeAnalysis;
-
namespace SyntheticVendorNamespace;
-[SuppressMessage("Security", "SCS0005:Weak random number generator.", Justification = "Acceptable for tests")]
-
public class SyntheticVendor : Vendor
{
@@ -101,6 +98,25 @@ public class SyntheticVendor : Vendor
}
+ public static VendorMetaData GetVendorMetaData()
+ {
+ return new VendorMetaData()
+ {
+ VendorName = "Synthetic Vendor",
+ VendorDescription = "A synthetic vendor for testing and demonstration purposes",
+ GetDefaultConnections = () =>
+ {
+ var defaultConnection = Vendor.CreateDefaultConnectionInfo(
+ "Synthetic Connection",
+ "Synthetic Vendor",
+ "", // Replace with actual path if you have a logo
+ allowCreateCustomConnections: true
+ );
+ return new List { defaultConnection };
+ }
+ };
+ }
+
private MessageSymbol CreateMessageSymbol(
string id,
string name,
@@ -131,24 +147,7 @@ public class SyntheticVendor : Vendor
return messageSymbol;
}
- public static VendorMetaData GetVendorMetaData()
- {
- return new VendorMetaData()
- {
- VendorName = "Synthetic Vendor",
- VendorDescription = "A synthetic vendor for testing and demonstration purposes",
- GetDefaultConnections = () =>
- {
- var defaultConnection = Vendor.CreateDefaultConnectionInfo(
- "Synthetic Connection",
- "Synthetic Vendor",
- "", // Replace with actual path if you have a logo
- allowCreateCustomConnections: true
- );
- return new List { defaultConnection };
- }
- };
- }
+
private MessageSymbol CreateMessageSymbol(string id, string name, string exchangeId, string assetId, SymbolType type)
@@ -226,20 +225,6 @@ public class SyntheticVendor : Vendor
}
-
-
- public override void OnConnected(CancellationToken token)
- {
- // This method is called after a successful connection
- // You can initialize resources or start any necessary processes here
- base.OnConnected(token);
-
- // For example, you might want to push some initial messages or data
- // PushMessage(new MessageVendorEvent("SyntheticVendor connected successfully"));
- }
-
-
-
public override IList GetExchanges(CancellationToken token)
{
return exchanges;
@@ -310,7 +295,6 @@ public class SyntheticVendor : Vendor
{
switch (symbolId)
{
- //case "W0": return GenerateConstant;
case "W1": return GenerateSpike;
case "W2": return GenerateDiracDelta;
case "W3": return GenerateSquareWave;
@@ -333,36 +317,52 @@ public class SyntheticVendor : Vendor
}
}
+/*
public override HistoryMetadata GetHistoryMetadata(CancellationToken cancellationToken)
{
- return new HistoryMetadata()
+ return new HistoryMetadata
{
- AllowedHistoryTypes = new HistoryType[]
+ AllowedAggregations = new string[] { "Time", "Tick" },
+ AllowedPeriodsHistoryAggregationTime = new Period[]
{
- HistoryType.Bid,
- HistoryType.Ask,
- HistoryType.Midpoint,
- HistoryType.Last,
- HistoryType.BidAsk,
- HistoryType.Mark,
+ Period.SECOND1, Period.SECOND5, Period.SECOND10, Period.SECOND15, Period.SECOND30,
+ Period.MIN1, Period.MIN2, Period.MIN3, Period.MIN4, Period.MIN5,
+ Period.MIN10, Period.MIN15, Period.MIN30,
+ Period.HOUR1, Period.HOUR2, Period.HOUR3, Period.HOUR4,
+ Period.HOUR6, Period.HOUR8, Period.HOUR12,
+ Period.DAY1,
+ Period.WEEK1,
+ Period.MONTH1,
+ Period.YEAR1
},
- AllowedPeriods = new Period[]
+ AllowedBasePeriodsHistoryAggregationTime = new BasePeriod[]
{
- Period.TICK1,
- Period.SECOND1, Period.SECOND5, Period.SECOND10, Period.SECOND15, Period.SECOND30,
- Period.MIN1, Period.MIN2, Period.MIN3, Period.MIN4, Period.MIN5,
- Period.MIN10, Period.MIN15, Period.MIN30,
- Period.HOUR1, Period.HOUR2, Period.HOUR3, Period.HOUR4,
- Period.HOUR6, Period.HOUR8, Period.HOUR12,
- Period.DAY1,
- Period.WEEK1,
- Period.MONTH1,
- Period.YEAR1
+ BasePeriod.Second, BasePeriod.Minute, BasePeriod.Hour, BasePeriod.Day, BasePeriod.Week, BasePeriod.Month, BasePeriod.Year
},
- UseHistoryLocalCache = false
+ AllowedHistoryTypesHistoryAggregationTime = new HistoryType[]
+ {
+ HistoryType.Bid,
+ HistoryType.Ask,
+ HistoryType.Midpoint,
+ HistoryType.Last,
+ HistoryType.BidAsk,
+ HistoryType.Mark
+ },
+ AllowedHistoryTypesHistoryAggregationTick = new HistoryType[]
+ {
+ HistoryType.Bid,
+ HistoryType.Ask,
+ HistoryType.Midpoint,
+ HistoryType.Last,
+ HistoryType.BidAsk,
+ HistoryType.Mark
+ },
+ DegreeOfParallelism = 1,
+ UseHistoryLocalCache = false,
+ BuildUncompletedBars = true
};
}
-
+*/
/*******************************************************************************************************************************************/
/*******************************************************************************************************************************************/
@@ -418,18 +418,6 @@ public class SyntheticVendor : Vendor
-
- private static readonly double[] distributionValues = new double[]
- {
- 0.010, // Extreme left tail
- 0.050, // Left tail
- 0.200, // Left of center
- 0.480, // Center (peak)
- 0.200, // Right of center
- 0.050, // Right tail
- 0.010 // Extreme right tail
- };
-
private HistoryItemBar GenerateDiracDelta(DateTime time, TimeSpan slice)
{
// Ensure we're working with UTC time
@@ -972,7 +960,7 @@ public class SyntheticVendor : Vendor
private const int NumOctaves = 6;
- private double[] pinkNoiseState = new double[NumOctaves];
+ private readonly double[] pinkNoiseState = new double[NumOctaves];
private double GeneratePinkNoiseValue()
{
double total = 0;
@@ -1033,8 +1021,8 @@ public class SyntheticVendor : Vendor
private double GBMLastClose = 100; // Starting price
- private double GBMMu = 0.05; // Annual drift
- private double GBMSigma = 0.2; // Annual volatility
+ private readonly double GBMMu = 0.05; // Annual drift
+ private readonly double GBMSigma = 0.2; // Annual volatility
private HistoryItemBar GenerateGBM(DateTime time, TimeSpan slice)
{
@@ -1081,9 +1069,9 @@ public class SyntheticVendor : Vendor
}
private double FBMLastClose = 100; // Starting price
- private double FBMHurst = 0.85; // Hurst parameter (0.5 < H < 1 for persistent fBm)
- private double FBMSigma = 0.25; // Volatility parameter
- private double FBMDrift = 0.001; // drift
+ private readonly double FBMHurst = 0.85; // Hurst parameter (0.5 < H < 1 for persistent fBm)
+ private readonly double FBMSigma = 0.25; // Volatility parameter
+ private readonly double FBMDrift = 0.001; // drift
private HistoryItemBar GenerateFBM(DateTime time, TimeSpan slice)
{
diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj
index da2d0d68..18f54f05 100644
--- a/Tests/Tests.csproj
+++ b/Tests/Tests.csproj
@@ -37,7 +37,10 @@
-
+
+
+
+
diff --git a/Tests/test_quantower.cs b/Tests/test_quantower.cs
index fc7e9058..a82e0cbb 100644
--- a/Tests/test_quantower.cs
+++ b/Tests/test_quantower.cs
@@ -1,7 +1,13 @@
+extern alias volatility;
+extern alias averages;
+extern alias statistics;
+
using Xunit;
-using System;
using System.Reflection;
using TradingPlatform.BusinessLayer;
+using statistics::QuanTAlib;
+using averages::QuanTAlib;
+using volatility::QuanTAlib;
namespace QuanTAlib
{
@@ -83,7 +89,7 @@ namespace QuanTAlib
[Fact] public void Slope() => TestIndicator("slope");
[Fact] public void Stddev() => TestIndicator("stddev");
[Fact] public void Variance() => TestIndicator("variance");
- [Fact] public void Zscore() => TestIndicator("zScore");
+ [Fact] public void Zscore() => TestIndicator("zScore");
// Volatility Indicators
[Fact] public void Atr() => TestIndicator("atr");
diff --git a/quantower/AbstractIndicatorBase.cs b/quantower/AbstractIndicatorBase.cs
deleted file mode 100644
index 0f650904..00000000
--- a/quantower/AbstractIndicatorBase.cs
+++ /dev/null
@@ -1,148 +0,0 @@
-using System.Drawing;
-using TradingPlatform.BusinessLayer;
-using TradingPlatform.BusinessLayer.Chart;
-using System.Runtime.CompilerServices;
-using System.Drawing.Drawing2D;
-namespace QuanTAlib;
-
-#pragma warning disable CA1416 // Validate platform compatibility
-public abstract class AbstractIndicatorBase : Indicator
-{
-
- [InputParameter("Data source", sortIndex: 18, variants: new object[]{
- "Close", PriceType.Close,
- "Open", PriceType.Open,
- "High", PriceType.High,
- "Low", PriceType.Low,
- "Typical", PriceType.Typical,
- "Median", PriceType.Median,
- "Weighted", PriceType.Weighted
- })]
- public PriceType SourcePrice { get; set; } = PriceType.Close;
-
- [InputParameter(name: "Line smoothing", sortIndex: 19, minimum: 0.0, maximum: 1.0, increment: 0.1, decimalPlaces: 2)]
- public double Tension = 0.2;
-
- [InputParameter("Show cold values", sortIndex: 20)]
- public bool ShowColdValues { get; set; } = true;
-
- // LineSeries.LineSeries(string, Color, int, LineStyle)'
-
- protected LineSeries? Series;
- protected abstract AbstractBase MovingAverage { get; }
-
- protected AbstractIndicatorBase() : base()
- {
- OnBackGround = true;
- SeparateWindow = false;
- Series = new(name: $"Name", color: Color.Orange, width: 2, style: LineStyle.Solid);
- AddLineSeries(Series);
-
- InitIndicator();
- }
-
- protected virtual void InitIndicator()
- {
- }
-
- protected override void OnInit()
- {
- InitIndicator();
- base.OnInit();
- }
-
- protected override void OnUpdate(UpdateArgs args)
- {
- base.OnUpdate(args);
- bool isNew = this.HistoricalData.Aggregation.GetPeriod == Period.TICK1
- ? args.Reason == UpdateReason.NewTick || args.Reason == UpdateReason.HistoricalBar
- : args.Reason == UpdateReason.NewBar || args.Reason == UpdateReason.HistoricalBar;
- double price = GetPrice(SourcePrice);
-
- TValue input = new TValue(Time(), price, isNew);
- TValue result = MovingAverage.Calc(input);
-
- Series!.SetMarker(0, Color.Transparent);
- Series.SetValue(result.Value);
-
- }
-
- public override void OnPaintChart(PaintChartEventArgs args)
- {
- base.OnPaintChart(args);
- List allPoints = new List();
- if (CurrentChart == null) return;
-
- Graphics gr = args.Graphics;
- var mainWindow = CurrentChart.MainWindow;
- 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 - MovingAverage.WarmupPeriod - rightIndex);
- }
- }
-
- private void DrawSmoothCombinedCurve(Graphics gr, List 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)Tension);
- }
-
- // 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)Tension);
- }
- }
- }
-
- protected 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));
- }
-
- private 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,
- };
- }
-}
\ No newline at end of file
diff --git a/quantower/Averages/AfirmaIndicator.cs b/quantower/Averages/AfirmaIndicator.cs
index 3163b30b..c3f3fc75 100644
--- a/quantower/Averages/AfirmaIndicator.cs
+++ b/quantower/Averages/AfirmaIndicator.cs
@@ -1,7 +1,9 @@
+using System.Drawing;
using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class AfirmaIndicator : IndicatorBase
+public class AfirmaIndicator : Indicator, IWatchlistIndicator
{
[InputParameter("Taps (number of weights)", sortIndex: 1, 1, 2000, 1, 0)]
public int Taps { get; set; } = 6;
@@ -11,27 +13,59 @@ public class AfirmaIndicator : IndicatorBase
[InputParameter("Window Type", sortIndex: 3, variants: [
"Rectangular", Afirma.WindowType.Rectangular,
- "Hanning", Afirma.WindowType.Hanning1,
- "Hamming", Afirma.WindowType.Hanning2,
- "Blackman", Afirma.WindowType.Blackman,
- "Blackman-Harris", Afirma.WindowType.BlackmanHarris
+ "Hanning", Afirma.WindowType.Hanning1,
+ "Hamming", Afirma.WindowType.Hanning2,
+ "Blackman", Afirma.WindowType.Blackman,
+ "Blackman-Harris", Afirma.WindowType.BlackmanHarris
])]
public Afirma.WindowType Window { get; set; } = Afirma.WindowType.Hanning1;
+ [InputParameter("Data source", sortIndex: 4, 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 Afirma? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"AFIRMA {Taps}:{Periods}:{Window} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods + Taps;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
public AfirmaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "AFIRMA - Adaptive Finite Impulse Response Moving Average";
Description = "Adaptive Finite Impulse Response Moving Average with ARMA component";
+ Series = new(name: $"AFIRMA {Taps}:{Periods}:{Window}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- base.InitIndicator();
ma = new Afirma(periods: Periods, taps: Taps, window: Window);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"AFIRMA {Taps}:{Periods}:{Window}:{SourceName}";
}
+
diff --git a/quantower/Averages/AlmaIndicator.cs b/quantower/Averages/AlmaIndicator.cs
index 7843a0c5..bc8781d1 100644
--- a/quantower/Averages/AlmaIndicator.cs
+++ b/quantower/Averages/AlmaIndicator.cs
@@ -1,30 +1,64 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class AlmaIndicator : IndicatorBase
+public class AlmaIndicator : Indicator, IWatchlistIndicator
{
[InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
public int Period { get; set; } = 10;
- [InputParameter("Offset", sortIndex: 5)]
+ [InputParameter("Offset", sortIndex: 2)]
public double Offset { get; set; } = 0.85;
- [InputParameter("Sigma", sortIndex: 6)]
+ [InputParameter("Sigma", sortIndex: 3)]
public double Sigma { get; set; } = 6.0;
- private Alma? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"ALMA {Period} : {Offset:F2} : {Sigma:F0} : {SourceName}";
- public AlmaIndicator() : base()
+ [InputParameter("Data source", sortIndex: 4, 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 Alma? ma;
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Period;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
+
+ public AlmaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "ALMA - Arnaud Legoux Moving Average";
Description = "Arnaud Legoux Moving Average";
-
+ Series = new(name: $"ALMA {Period}:{Offset:F2}:{Sigma:F0}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- base.InitIndicator();
ma = new Alma(period: Period, offset: Offset, sigma: Sigma);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"ALMA {Period}:{Offset:F2}:{Sigma:F0}:{SourceName}";
}
diff --git a/quantower/Averages/DemaIndicator.cs b/quantower/Averages/DemaIndicator.cs
index f11d5ce4..d7777af1 100644
--- a/quantower/Averages/DemaIndicator.cs
+++ b/quantower/Averages/DemaIndicator.cs
@@ -1,23 +1,58 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class DemaIndicator : IndicatorBase
+public class DemaIndicator : Indicator, IWatchlistIndicator
{
[InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
public int Period { get; set; } = 10;
- private Dema? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"DEMA {Period} : {SourceName}";
- public DemaIndicator() : base()
+ [InputParameter("Data source", sortIndex: 2, 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 Dema? ma;
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Period;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
+
+ public DemaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "DEMA - Double Exponential Moving Average";
Description = "A faster-responding moving average that reduces lag by applying the EMA twice.";
+ Series = new(name: $"DEMA {Period}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- base.InitIndicator();
ma = new Dema(period: Period);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"DEMA {Period}:{SourceName}";
}
diff --git a/quantower/Averages/DsmaIndicator.cs b/quantower/Averages/DsmaIndicator.cs
index cc14789d..b860bb62 100644
--- a/quantower/Averages/DsmaIndicator.cs
+++ b/quantower/Averages/DsmaIndicator.cs
@@ -1,27 +1,63 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class DsmaIndicator : IndicatorBase
+public class DsmaIndicator : Indicator, IWatchlistIndicator
{
[InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
public int Period { get; set; } = 10;
+
[InputParameter("Scale factor", sortIndex: 2, minimum: 0.01, maximum: 1.0, increment: 0.01, decimalPlaces: 2)]
public double Scale { get; set; } = 0.5;
- private Dsma? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"DSMA {Period} : {Scale:F2} : {SourceName}";
+ [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;
- public DsmaIndicator() : base()
+ private Dsma? ma;
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths { get; private set; }
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
+
+ public DsmaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "DSMA - Deviation Scaled Moving Average";
Description = "A moving average that adjusts its responsiveness based on price deviations from the mean.";
+ Series = new(name: $"DSMA {Period}:{Scale:F2}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
ma = new Dsma(Period, Scale);
MinHistoryDepths = ma.WarmupPeriod;
- base.InitIndicator();
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"DSMA {Period}:{Scale:F2}:{SourceName}";
}
+
diff --git a/quantower/Averages/DwmaIndicator.cs b/quantower/Averages/DwmaIndicator.cs
index a1f3be2b..a78292ea 100644
--- a/quantower/Averages/DwmaIndicator.cs
+++ b/quantower/Averages/DwmaIndicator.cs
@@ -1,24 +1,59 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class DwmaIndicator : IndicatorBase
+public class DwmaIndicator : Indicator, IWatchlistIndicator
{
[InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
public int Period { get; set; } = 10;
- private Dwma? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"DWMA {Period} : {SourceName}";
+ [InputParameter("Data source", sortIndex: 2, 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;
- public DwmaIndicator() : base()
+ private Dwma? ma;
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Period;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
+
+ public DwmaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "DWMA - Double Weighted Moving Average";
Description = "A moving average that applies double weighting to recent prices for increased responsiveness.";
+ Series = new(name: $"DWMA {Period}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
ma = new Dwma(Period);
- base.InitIndicator();
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"DWMA {Period}:{SourceName}";
}
+
diff --git a/quantower/Averages/EmaIndicator.cs b/quantower/Averages/EmaIndicator.cs
index 5d8fc937..657388d8 100644
--- a/quantower/Averages/EmaIndicator.cs
+++ b/quantower/Averages/EmaIndicator.cs
@@ -1,27 +1,58 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class EmaIndicator : IndicatorBase
+public class EmaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
- [InputParameter("Use SMA for warmup", sortIndex: 5)]
- public bool UseSma { get; set; } = false;
+ [InputParameter("Data source", sortIndex: 2, 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 Ema? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"EMA {Period} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public EmaIndicator() : base()
+ public EmaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "EMA - Exponential Moving Average";
- Description = "Moving average that gives more weight to recent prices, reducing lag in trend following.";
+ Description = "Exponential Moving Average";
+ Series = new(name: $"EMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- base.InitIndicator();
- ma = new Ema(period: Period, useSma: UseSma);
+ ma = new Ema(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"EMA {Periods}:{SourceName}";
}
diff --git a/quantower/Averages/EpmaIndicator.cs b/quantower/Averages/EpmaIndicator.cs
index 5fee343d..e5fdad82 100644
--- a/quantower/Averages/EpmaIndicator.cs
+++ b/quantower/Averages/EpmaIndicator.cs
@@ -1,24 +1,58 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class EpmaIndicator : IndicatorBase
+public class EpmaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Epma? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"EPMA {Period} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public EpmaIndicator() : base()
+ public EpmaIndicator()
{
- Name = "EPMA - Endpoint Moving Average";
- Description = "Moving average that emphasizes the most recent data point, useful for identifying trend changes.";
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
+ Name = "EPMA - Exponential Percentage Moving Average";
+ Description = "Exponential Percentage Moving Average";
+ Series = new(name: $"EPMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- base.InitIndicator();
- ma = new Epma(period: Period);
+ ma = new Epma(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"EPMA {Periods}:{SourceName}";
}
diff --git a/quantower/Averages/FramaIndicator.cs b/quantower/Averages/FramaIndicator.cs
index 9a1959ca..df848cd8 100644
--- a/quantower/Averages/FramaIndicator.cs
+++ b/quantower/Averages/FramaIndicator.cs
@@ -1,24 +1,58 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class FramaIndicator : IndicatorBase
+public class FramaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 2, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Frama? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"FRAMA {Period} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods * 2;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public FramaIndicator() : base()
+ public FramaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "FRAMA - Fractal Adaptive Moving Average";
- Description = "Adaptive moving average that adjusts its smoothing based on market fractal dimension.";
+ Description = "Fractal Adaptive Moving Average";
+ Series = new(name: $"FRAMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- ma = new Frama(Period);
- base.InitIndicator();
+ ma = new Frama(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"FRAMA {Periods}:{SourceName}";
}
diff --git a/quantower/Averages/FwmaIndicator.cs b/quantower/Averages/FwmaIndicator.cs
index 4dee3a20..4a9af703 100644
--- a/quantower/Averages/FwmaIndicator.cs
+++ b/quantower/Averages/FwmaIndicator.cs
@@ -1,24 +1,58 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class FwmaIndicator : IndicatorBase
+public class FwmaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Fwma? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"FWMA {Period} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public FwmaIndicator() : base()
+ public FwmaIndicator()
{
- Name = "FWMA - Fibonacci-Weighted Moving Average";
- Description = "Moving average that uses Fibonacci sequence for weighting, emphasizing recent and key historical prices.";
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
+ Name = "FWMA - Fibonacci Weighted Moving Average";
+ Description = "Fibonacci Weighted Moving Average";
+ Series = new(name: $"FWMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- ma = new Fwma(Period);
- base.InitIndicator();
+ ma = new Fwma(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"FWMA {Periods}:{SourceName}";
}
diff --git a/quantower/Averages/GmaIndicator.cs b/quantower/Averages/GmaIndicator.cs
index cbbd2ad0..6bc0453f 100644
--- a/quantower/Averages/GmaIndicator.cs
+++ b/quantower/Averages/GmaIndicator.cs
@@ -1,24 +1,61 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class GmaIndicator : IndicatorBase
+public class GmaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
+
+ [InputParameter("Sigma", sortIndex: 2, 0.1, 10, 0.1, 1)]
+ public double Sigma { get; set; } = 1.0;
+
+ [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;
private Gma? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"GMA {Period} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public GmaIndicator() : base()
+ public GmaIndicator()
{
- Name = "GMA - Gaussian-Weighted Moving Average";
- Description = "Moving average using Gaussian distribution for weighting, balancing recent and historical data.";
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
+ Name = "GMA - Gaussian Moving Average";
+ Description = "Gaussian Moving Average";
+ Series = new(name: $"GMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- ma = new Gma(Period);
- base.InitIndicator();
+ ma = new Gma(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"GMA {Periods}:{Sigma}:{SourceName}";
}
diff --git a/quantower/Averages/HmaIndicator.cs b/quantower/Averages/HmaIndicator.cs
index e255579c..842f327f 100644
--- a/quantower/Averages/HmaIndicator.cs
+++ b/quantower/Averages/HmaIndicator.cs
@@ -1,24 +1,58 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class HmaIndicator : IndicatorBase
+public class HmaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 2, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Hma? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"HMA {Period} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods + (int)Math.Sqrt(Periods) - 1;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public HmaIndicator() : base()
+ public HmaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "HMA - Hull Moving Average";
- Description = "Responsive moving average that reduces lag while maintaining smoothness in price action.";
+ Description = "Hull Moving Average";
+ Series = new(name: $"HMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- ma = new Hma(Period);
- base.InitIndicator();
+ ma = new Hma(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"HMA {Periods}:{SourceName}";
}
diff --git a/quantower/Averages/HtitIndicator.cs b/quantower/Averages/HtitIndicator.cs
index b619134f..bf1b1f8a 100644
--- a/quantower/Averages/HtitIndicator.cs
+++ b/quantower/Averages/HtitIndicator.cs
@@ -1,22 +1,55 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class HtitIndicator : IndicatorBase
+public class HtitIndicator : Indicator, IWatchlistIndicator
{
- private Htit? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"HTIT : {SourceName}";
+ [InputParameter("Data source", sortIndex: 1, 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;
- public HtitIndicator() : base()
+ private Htit? ma;
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => 12; // Based on WarmupPeriod in Htit
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
+
+ public HtitIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "HTIT - Hilbert Transform Instantaneous Trendline";
- Description = "Uses Hilbert Transform to identify the dominant cycle and generate a smooth, lag-free trendline.";
+ Description = "Hilbert Transform Instantaneous Trendline (Note: This indicator may not be fully functional)";
+ Series = new(name: "HTIT", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
ma = new Htit();
- MinHistoryDepths = ma.WarmupPeriod;
- base.InitIndicator();
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"HTIT:{SourceName}";
}
diff --git a/quantower/Averages/HwmaIndicator.cs b/quantower/Averages/HwmaIndicator.cs
index 4c36f17a..fd76600a 100644
--- a/quantower/Averages/HwmaIndicator.cs
+++ b/quantower/Averages/HwmaIndicator.cs
@@ -1,30 +1,74 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class HwmaIndicator : IndicatorBase
+public class HwmaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("nA - smoothed series", sortIndex: 5, minimum: 0.0, maximum: 1.0, increment: 0.1, decimalPlaces: 2)]
- public double nA { get; set; } = 0.18;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
- [InputParameter("nB - assess the trend (from 0 to 1)", sortIndex: 6, minimum: 0.0, maximum: 1.0, increment: 0.1, decimalPlaces: 2)]
- public double nB { get; set; } = 0.1;
+ [InputParameter("nA", sortIndex: 2, 0, 1, 0.01, 2)]
+ public double NA { get; set; } = 0;
- [InputParameter("nC - assess seasonality (from 0 to 1)", sortIndex: 7, minimum: 0.0, maximum: 1.0, increment: 0.1, decimalPlaces: 2)]
- public double nC { get; set; } = 0.1;
+ [InputParameter("nB", sortIndex: 3, 0, 1, 0.01, 2)]
+ public double NB { get; set; } = 0;
+
+ [InputParameter("nC", sortIndex: 4, 0, 1, 0.01, 2)]
+ public double NC { get; set; } = 0;
+
+ [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 Hwma? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"HWMA {nA:F2} : {nB:F2} : {nC:F2} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public HwmaIndicator() : base()
+ public HwmaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "HWMA - Holt-Winter Moving Average";
- Description = "Triple exponential moving average that accounts for level, trend, and seasonal components.";
+ Description = "Holt-Winter Moving Average";
+ Series = new(name: $"HWMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- ma = new Hwma(nA: nA, nB: nB, nC: nC);
- base.InitIndicator();
+ if (NA == 0 && NB == 0 && NC == 0)
+ {
+ ma = new Hwma(Periods);
+ }
+ else
+ {
+ ma = new Hwma(Periods, NA, NB, NC);
+ }
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"HWMA {Periods}:{NA}:{NB}:{NC}:{SourceName}";
}
diff --git a/quantower/Averages/JmaIndicator.cs b/quantower/Averages/JmaIndicator.cs
index a80f9fc7..777ec8ee 100644
--- a/quantower/Averages/JmaIndicator.cs
+++ b/quantower/Averages/JmaIndicator.cs
@@ -1,26 +1,64 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class JmaIndicator : IndicatorBase
+public class JmaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 2, 2000, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
[InputParameter("Phase", sortIndex: 2, -100, 100, 1, 0)]
- public int Phase { get; set; } = 0;
+ public double Phase { get; set; } = 0;
+
+ [InputParameter("VShort", sortIndex: 3, 1, 100, 1, 0)]
+ public int VShort { get; set; } = 10;
+
+ [InputParameter("Data source", sortIndex: 4, 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? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"JMA {Period} : {Phase} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods * 2;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public JmaIndicator() : base()
+ public JmaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "JMA - Jurik Moving Average";
- Description = "Adaptive moving average with reduced lag and noise, adjustable smoothness and phase shift.";
+ Description = "Jurik Moving Average (Note: This indicator may have consistency issues)";
+ Series = new(name: $"JMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- ma = new Jma(period: Period, phase: (double)Phase);
- base.InitIndicator();
+ ma = new Jma(Periods, Phase, VShort);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"JMA {Periods}:{Phase}:{VShort}:{SourceName}";
}
diff --git a/quantower/Averages/KamaIndicator.cs b/quantower/Averages/KamaIndicator.cs
index 028ca796..c6ba1abb 100644
--- a/quantower/Averages/KamaIndicator.cs
+++ b/quantower/Averages/KamaIndicator.cs
@@ -1,28 +1,64 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class KamaIndicator : IndicatorBase
+public class KamaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
- [InputParameter("Fast", sortIndex: 2, 1, 2000, 1, 0)]
+ [InputParameter("Fast", sortIndex: 2, 1, 100, 1, 0)]
public int Fast { get; set; } = 2;
- [InputParameter("Slow", sortIndex: 3, 1, 2000, 1, 0)]
+
+ [InputParameter("Slow", sortIndex: 3, 1, 100, 1, 0)]
public int Slow { get; set; } = 30;
+
+ [InputParameter("Data source", sortIndex: 4, 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 Kama? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"KAMA {Period} : {Fast} : {Slow} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public KamaIndicator() : base()
+ public KamaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "KAMA - Kaufman's Adaptive Moving Average";
- Description = "Adaptive moving average that adjusts to market volatility, reducing lag in trending markets.";
+ Description = "Kaufman's Adaptive Moving Average";
+ Series = new(name: $"KAMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- ma = new Kama(Period, Fast, Slow);
- base.InitIndicator();
+ ma = new Kama(Periods, Fast, Slow);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"KAMA {Periods}:{Fast}:{Slow}:{SourceName}";
}
diff --git a/quantower/Averages/LtmaIndicator.cs b/quantower/Averages/LtmaIndicator.cs
index ebf29dc5..9682a3fe 100644
--- a/quantower/Averages/LtmaIndicator.cs
+++ b/quantower/Averages/LtmaIndicator.cs
@@ -1,24 +1,58 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class LtmaIndicator : IndicatorBase
+public class LtmaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Gamma", sortIndex: 1, 0, 1, 0.01, 2)]
- public double Gamma { get; set; } = 0.10;
+ [InputParameter("Gamma", sortIndex: 1, 0.01, 1, 0.01, 2)]
+ public double Gamma { get; set; } = 0.1;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Ltma? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"Laguerre {Gamma:F2} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => 4; // Based on WarmupPeriod in Ltma
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public LtmaIndicator() : base()
+ public LtmaIndicator()
{
- Name = "LTMA - Laguerre Transform Moving Average";
- Description = "Moving average using Laguerre polynomials, offering adjustable smoothing and lag reduction.";
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
+ Name = "LTMA - Laguerre Time Moving Average";
+ Description = "Laguerre Time Moving Average";
+ Series = new(name: $"LTMA {Gamma}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- ma = new Ltma(gamma: Gamma);
- base.InitIndicator();
+ ma = new Ltma(Gamma);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"LTMA {Gamma}:{SourceName}";
}
diff --git a/quantower/Averages/MaafIndicator.cs b/quantower/Averages/MaafIndicator.cs
index 49a94d01..7cde3f58 100644
--- a/quantower/Averages/MaafIndicator.cs
+++ b/quantower/Averages/MaafIndicator.cs
@@ -1,27 +1,61 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class MaafIndicator : IndicatorBase
+public class MaafIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 39;
+ [InputParameter("Periods", sortIndex: 1, 3, 1000, 1, 0)]
+ public int Periods { get; set; } = 39;
- [InputParameter("Threshold", sortIndex: 5, minimum: 0, maximum: 1, increment: 0.001, decimalPlaces: 3)]
- private double Threshold { get; set; } = 0.002;
+ [InputParameter("Threshold", sortIndex: 2, 0.0001, 0.1, 0.0001, 4)]
+ public double Threshold { get; set; } = 0.002;
+
+ [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;
private Maaf? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"MAAF {Period} : {Threshold:F2} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public MaafIndicator() : base()
+ public MaafIndicator()
{
- Name = "MAAF - Median-Average Adaptive Filter";
- Description = "Adaptive filter combining median and average, reducing noise while preserving trend responsiveness.";
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
+ Name = "MAAF - Median Adaptive Averaging Filter";
+ Description = "Median Adaptive Averaging Filter (Note: This indicator may have consistency issues)";
+ Series = new(name: $"MAAF {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- base.InitIndicator();
- ma = new Maaf(period: Period, threshold: Threshold);
+ ma = new Maaf(Periods, Threshold);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"MAAF {Periods}:{Threshold}:{SourceName}";
}
diff --git a/quantower/Averages/MamaIndicator.cs b/quantower/Averages/MamaIndicator.cs
index 3f243e0a..0c19be79 100644
--- a/quantower/Averages/MamaIndicator.cs
+++ b/quantower/Averages/MamaIndicator.cs
@@ -1,25 +1,65 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class MamaIndicator : IndicatorBase
+public class MamaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Fast limit", sortIndex: 2, 0, 1, 0.01, 2)]
- public double Fast { get; set; } = 0.4;
- [InputParameter("Slow limit", sortIndex: 3, 0, 1, 0.01, 2)]
- public double Slow { get; set; } = 0.04;
+ [InputParameter("Fast Limit", sortIndex: 1, 0.01, 1, 0.01, 2)]
+ public double FastLimit { get; set; } = 0.5;
+
+ [InputParameter("Slow Limit", sortIndex: 2, 0.01, 1, 0.01, 2)]
+ public double SlowLimit { get; set; } = 0.05;
+
+ [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;
+
private Mama? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"MAMA : {Fast} : {Slow} : {SourceName}";
+ protected LineSeries? MamaSeries;
+ protected LineSeries? FamaSeries;
+ protected string? SourceName;
+ public int MinHistoryDepths => 6;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public MamaIndicator() : base()
+ public MamaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "MAMA - MESA Adaptive Moving Average";
- Description = "Adaptive moving average using MESA algorithm to adjust to market cycles and reduce lag.";
+ Description = "MESA Adaptive Moving Average";
+ MamaSeries = new(name: "MAMA", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ FamaSeries = new(name: "FAMA", color: Color.Red, width: 2, style: LineStyle.Solid);
+ AddLineSeries(MamaSeries);
+ AddLineSeries(FamaSeries);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- ma = new Mama(Fast, Slow);
- base.InitIndicator();
+ ma = new Mama(FastLimit, SlowLimit);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ MamaSeries!.SetValue(result.Value);
+ FamaSeries!.SetValue(ma.Fama.Value);
+ }
+
+ public override string ShortName => $"MAMA {FastLimit}:{SlowLimit}:{SourceName}";
}
diff --git a/quantower/Averages/MgdiIndicator.cs b/quantower/Averages/MgdiIndicator.cs
index 525c449b..f8ea96df 100644
--- a/quantower/Averages/MgdiIndicator.cs
+++ b/quantower/Averages/MgdiIndicator.cs
@@ -1,27 +1,61 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class MgdiIndicator : IndicatorBase
+public class MgdiIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
- [InputParameter("k Factor", sortIndex: 2, minimum: 0.0, maximum: 1.0, increment: 0.1, decimalPlaces: 2)]
- public double kfactor { get; set; } = 0.6;
+ [InputParameter("K-Factor", sortIndex: 2, 0.1, 2, 0.1, 1)]
+ public double KFactor { get; set; } = 0.6;
+
+ [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;
private Mgdi? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"MGDI {Period} : {kfactor:F2} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public MgdiIndicator() : base()
+ public MgdiIndicator()
{
- Name = "MGDI - McGinley Dynamic Index";
- Description = "Adaptive moving average that adjusts to market speed, reducing whipsaws in trending markets.";
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
+ Name = "MGDI - McGinley Dynamic Indicator";
+ Description = "McGinley Dynamic Indicator";
+ Series = new(name: $"MGDI {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- ma = new Mgdi(period: Period, kFactor: kfactor);
- base.InitIndicator();
+ ma = new Mgdi(Periods, KFactor);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"MGDI {Periods}:{KFactor}:{SourceName}";
}
diff --git a/quantower/Averages/MmaIndicator.cs b/quantower/Averages/MmaIndicator.cs
index b37cc874..71e59448 100644
--- a/quantower/Averages/MmaIndicator.cs
+++ b/quantower/Averages/MmaIndicator.cs
@@ -1,24 +1,58 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class MmaIndicator : IndicatorBase
+public class MmaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 2, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Mma? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"MMA {Period} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public MmaIndicator() : base()
+ public MmaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "MMA - Modified Moving Average";
- Description = "Variation of EMA that reduces lag and smooths price action, balancing responsiveness and stability.";
+ Description = "Modified Moving Average";
+ Series = new(name: $"MMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- base.InitIndicator();
- ma = new Mma(period: Period);
+ ma = new Mma(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"MMA {Periods}:{SourceName}";
}
diff --git a/quantower/Averages/PwmaIndicator.cs b/quantower/Averages/PwmaIndicator.cs
index fac30512..950dc051 100644
--- a/quantower/Averages/PwmaIndicator.cs
+++ b/quantower/Averages/PwmaIndicator.cs
@@ -1,24 +1,58 @@
+using System.Drawing;
using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class PwmaIndicator : IndicatorBase
+public class PwmaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Pwma? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"PWMA {Period} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public PwmaIndicator() : base()
+ public PwmaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "PWMA - Pascal's Weighted Moving Average";
- Description = "Moving average using Pascal's triangle coefficients, emphasizing recent data with smooth transitions.";
+ Description = "Pascal's Weighted Moving Average";
+ Series = new(name: $"PWMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- base.InitIndicator();
- ma = new Pwma(period: Period);
+ ma = new Pwma(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"PWMA {Periods}:{SourceName}";
}
diff --git a/quantower/Averages/QemaIndicator.cs b/quantower/Averages/QemaIndicator.cs
index c4403eea..5ce7d79d 100644
--- a/quantower/Averages/QemaIndicator.cs
+++ b/quantower/Averages/QemaIndicator.cs
@@ -1,30 +1,67 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class QemaIndicator : IndicatorBase
+public class QemaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("alpha 1", sortIndex: 1, minimum: 0.01, maximum: 1.0, increment: 0.01, decimalPlaces: 2)]
- public double k1 { get; set; } = 0.2;
+ [InputParameter("K1", sortIndex: 1, 0.01, 1, 0.01, 2)]
+ public double K1 { get; set; } = 0.2;
+
+ [InputParameter("K2", sortIndex: 2, 0.01, 1, 0.01, 2)]
+ public double K2 { get; set; } = 0.2;
+
+ [InputParameter("K3", sortIndex: 3, 0.01, 1, 0.01, 2)]
+ public double K3 { get; set; } = 0.2;
+
+ [InputParameter("K4", sortIndex: 4, 0.01, 1, 0.01, 2)]
+ public double K4 { get; set; } = 0.2;
+
+ [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("alpha 2", sortIndex: 2, minimum: 0.01, maximum: 1.0, increment: 0.01, decimalPlaces: 2)]
- public double k2 { get; set; } = 0.3;
- [InputParameter("alpha 3", sortIndex: 3, minimum: 0.01, maximum: 1.0, increment: 0.01, decimalPlaces: 2)]
- public double k3 { get; set; } = 0.4;
- [InputParameter("alpha 4", sortIndex: 4, minimum: 0.01, maximum: 1.0, increment: 0.01, decimalPlaces: 2)]
- public double k4 { get; set; } = 0.5;
private Qema? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"QEMA {k1:F2} : {k2:F2} : {k3:F2} : {k4:F2} :{SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => (int)((2 - Math.Min(Math.Min(K1, K2), Math.Min(K3, K4))) / Math.Min(Math.Min(K1, K2), Math.Min(K3, K4)));
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public QemaIndicator() : base()
+ public QemaIndicator()
{
- Name = "QEMA - Quad Exponential Moving Average";
- Description = "Combines four EMAs with different smoothing factors to reduce lag and improve trend following.";
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
+ Name = "QEMA - Quadruple Exponential Moving Average";
+ Description = "Quadruple Exponential Moving Average";
+ Series = new(name: $"QEMA {K1},{K2},{K3},{K4}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- base.InitIndicator();
- ma = new Qema(k1, k2, k3, k4);
+ ma = new Qema(K1, K2, K3, K4);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"QEMA {K1},{K2},{K3},{K4}:{SourceName}";
}
diff --git a/quantower/Averages/RemaIndicator.cs b/quantower/Averages/RemaIndicator.cs
index c8f50273..ea544d08 100644
--- a/quantower/Averages/RemaIndicator.cs
+++ b/quantower/Averages/RemaIndicator.cs
@@ -1,27 +1,61 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class RemaIndicator : IndicatorBase
+public class RemaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
- [InputParameter("Regularization Factor", sortIndex: 2, minimum: 0, maximum: 2.5, increment: 0.1, decimalPlaces: 1)]
+ [InputParameter("Lambda", sortIndex: 2, 0, 1, 0.01, 2)]
public double Lambda { get; set; } = 0.5;
+ [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;
+
private Rema? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"REMA {Period} : {Lambda:F2} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public RemaIndicator() : base()
+ public RemaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "REMA - Regularized Exponential Moving Average";
- Description = "EMA variant with regularization to reduce noise and improve stability in volatile markets.";
+ Description = "Regularized Exponential Moving Average";
+ Series = new(name: $"REMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- base.InitIndicator();
- ma = new Rema(period: Period, lambda: Lambda);
+ ma = new Rema(Periods, Lambda);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"REMA {Periods}:{Lambda}:{SourceName}";
}
diff --git a/quantower/Averages/RmaIndicator.cs b/quantower/Averages/RmaIndicator.cs
index 41b9e333..aadeabfa 100644
--- a/quantower/Averages/RmaIndicator.cs
+++ b/quantower/Averages/RmaIndicator.cs
@@ -1,24 +1,58 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class RmaIndicator : IndicatorBase
+public class RmaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Rma? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"RMA {Period} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods * 2;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public RmaIndicator() : base()
+ public RmaIndicator()
{
- Name = "RMA - Wilder's Moving Average";
- Description = "Smoothed moving average that reduces whipsaws, commonly used in RSI calculations.";
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
+ Name = "RMA - Relative Moving Average (Wilder's Moving Average)";
+ Description = "Relative Moving Average, also known as Wilder's Moving Average";
+ Series = new(name: $"RMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- ma = new Rma(Period);
- base.InitIndicator();
+ ma = new Rma(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"RMA {Periods}:{SourceName}";
}
diff --git a/quantower/Averages/SinemaIndicator.cs b/quantower/Averages/SinemaIndicator.cs
index 3ebeb128..306e66ae 100644
--- a/quantower/Averages/SinemaIndicator.cs
+++ b/quantower/Averages/SinemaIndicator.cs
@@ -1,24 +1,58 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class SinemaIndicator : IndicatorBase
+public class SinemaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Sinema? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"SINEMA {Period} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public SinemaIndicator() : base()
+ public SinemaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "SINEMA - Sine-Weighted Moving Average";
- Description = "Moving average using sine function for weighting, balancing recent and historical price data.";
+ Description = "Sine-Weighted Moving Average";
+ Series = new(name: $"SINEMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- ma = new Sinema(Period);
- base.InitIndicator();
+ ma = new Sinema(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"SINEMA {Periods}:{SourceName}";
}
diff --git a/quantower/Averages/SmaIndicator.cs b/quantower/Averages/SmaIndicator.cs
index a90e30a5..e71b97ae 100644
--- a/quantower/Averages/SmaIndicator.cs
+++ b/quantower/Averages/SmaIndicator.cs
@@ -1,24 +1,58 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class SmaIndicator : IndicatorBase
+public class SmaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Sma? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"SMA {Period} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public SmaIndicator() : base()
+ public SmaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "SMA - Simple Moving Average";
- Description = "Basic moving average that calculates the arithmetic mean of prices over a specified period.";
+ Description = "Simple Moving Average";
+ Series = new(name: $"SMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- ma = new Sma(Period);
- base.InitIndicator();
+ ma = new Sma(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"SMA {Periods}:{SourceName}";
}
diff --git a/quantower/Averages/SmmaIndicator.cs b/quantower/Averages/SmmaIndicator.cs
index 49186bfe..675e5c3f 100644
--- a/quantower/Averages/SmmaIndicator.cs
+++ b/quantower/Averages/SmmaIndicator.cs
@@ -1,24 +1,58 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class SmmaIndicator : IndicatorBase
+public class SmmaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Smma? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"SMMA {Period} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public SmmaIndicator() : base()
+ public SmmaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "SMMA - Smoothed Moving Average";
- Description = "Moving average that gives more weight to recent data while retaining all historical data.";
+ Description = "Smoothed Moving Average";
+ Series = new(name: $"SMMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- ma = new Smma(Period);
- base.InitIndicator();
+ ma = new Smma(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"SMMA {Periods}:{SourceName}";
}
diff --git a/quantower/Averages/T3Indicator.cs b/quantower/Averages/T3Indicator.cs
index 81dac3f4..d46f338c 100644
--- a/quantower/Averages/T3Indicator.cs
+++ b/quantower/Averages/T3Indicator.cs
@@ -1,30 +1,64 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class T3Indicator : IndicatorBase
+public class T3Indicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
- [InputParameter("Vfactor", sortIndex: 2, 0, 1, 0.01, 2)]
- public double Vfactor { get; set; } = 0.62;
+ [InputParameter("Volume Factor", sortIndex: 2, 0, 1, 0.01, 2)]
+ public double VolumeFactor { get; set; } = 0.7;
- [InputParameter("Use SMA for warmup", sortIndex: 3)]
- public bool UseSma { get; set; } = false;
+ [InputParameter("Use SMA", sortIndex: 3)]
+ public bool UseSma { get; set; } = true;
+
+ [InputParameter("Data source", sortIndex: 4, 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 T3? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"T3 {Period} : {Vfactor:F2} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public T3Indicator() : base()
+ public T3Indicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "T3 - Tillson T3 Moving Average";
- Description = "Triple exponential moving average with reduced lag and smoothing, adjustable via volume factor.";
+ Description = "Tillson T3 Moving Average";
+ Series = new(name: $"T3 {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- ma = new T3(period: Period, vfactor: Vfactor, useSma: UseSma);
- base.InitIndicator();
+ ma = new T3(Periods, VolumeFactor, UseSma);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"T3 {Periods}:{VolumeFactor}:{UseSma}:{SourceName}";
}
diff --git a/quantower/Averages/TemaIndicator.cs b/quantower/Averages/TemaIndicator.cs
index 236e893c..208cb0d1 100644
--- a/quantower/Averages/TemaIndicator.cs
+++ b/quantower/Averages/TemaIndicator.cs
@@ -1,24 +1,58 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class TemaIndicator : IndicatorBase
+public class TemaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Tema? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"TEMA {Period} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => (int)Math.Ceiling(-Periods * Math.Log(1 - 0.85));
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public TemaIndicator() : base()
+ public TemaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "TEMA - Triple Exponential Moving Average";
- Description = "Moving average that applies EMA three times to reduce lag and improve responsiveness to trends.";
+ Description = "Triple Exponential Moving Average";
+ Series = new(name: $"TEMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- base.InitIndicator();
- ma = new Tema(period: Period);
+ ma = new Tema(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"TEMA {Periods}:{SourceName}";
}
diff --git a/quantower/Averages/TrimaIndicator.cs b/quantower/Averages/TrimaIndicator.cs
index 2ac8d091..443331ec 100644
--- a/quantower/Averages/TrimaIndicator.cs
+++ b/quantower/Averages/TrimaIndicator.cs
@@ -1,24 +1,58 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class TrimaIndicator : IndicatorBase
+public class TrimaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Trima? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"TRIMA {Period} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public TrimaIndicator() : base()
+ public TrimaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "TRIMA - Triangular Moving Average";
- Description = "Weighted moving average giving more importance to the middle of the period for smoother output.";
+ Description = "Triangular Moving Average";
+ Series = new(name: $"TRIMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- ma = new Trima(Period);
- base.InitIndicator();
+ ma = new Trima(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"TRIMA {Periods}:{SourceName}";
}
diff --git a/quantower/Averages/VidyaIndicator.cs b/quantower/Averages/VidyaIndicator.cs
index b45c117c..a2b37948 100644
--- a/quantower/Averages/VidyaIndicator.cs
+++ b/quantower/Averages/VidyaIndicator.cs
@@ -1,28 +1,64 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class VidyaIndicator : IndicatorBase
+public class VidyaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Short Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 10;
- [InputParameter("Long Period", sortIndex: 2, 1, 2000, 1, 0)]
- public int LPeriod { get; set; } = 40;
- [InputParameter("Alpha", sortIndex: 3, 0, 1, 0.1, 1)]
- public double Alpha { get; set; } = 0.4;
+ [InputParameter("Short Period", sortIndex: 1, 1, 1000, 1, 0)]
+ public int ShortPeriod { get; set; } = 14;
+
+ [InputParameter("Long Period", sortIndex: 2, 0, 1000, 1, 0)]
+ public int LongPeriod { get; set; } = 0;
+
+ [InputParameter("Alpha", sortIndex: 3, 0.01, 1, 0.01, 2)]
+ public double Alpha { get; set; } = 0.2;
+
+ [InputParameter("Data source", sortIndex: 4, 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 Vidya? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"VIDYA {Period} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => LongPeriod == 0 ? ShortPeriod * 4 : LongPeriod;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public VidyaIndicator() : base()
+ public VidyaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "VIDYA - Variable Index Dynamic Average";
- Description = "Adaptive moving average that adjusts based on market volatility for improved trend following.";
+ Description = "Variable Index Dynamic Average";
+ Series = new(name: $"VIDYA {ShortPeriod}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- ma = new Vidya(Period, LPeriod, Alpha);
- base.InitIndicator();
+ ma = new Vidya(ShortPeriod, LongPeriod, Alpha);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"VIDYA {ShortPeriod}:{LongPeriod}:{Alpha}:{SourceName}";
}
diff --git a/quantower/Averages/WmaIndicator.cs b/quantower/Averages/WmaIndicator.cs
index aec32407..1c00b0ec 100644
--- a/quantower/Averages/WmaIndicator.cs
+++ b/quantower/Averages/WmaIndicator.cs
@@ -1,24 +1,58 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class WmaIndicator : IndicatorBase
+public class WmaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Wma? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"WMA {Period} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public WmaIndicator() : base()
+ public WmaIndicator()
{
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
Name = "WMA - Weighted Moving Average";
- Description = "Moving average that assigns higher weights to recent data points for improved responsiveness.";
+ Description = "Weighted Moving Average";
+ Series = new(name: $"WMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- ma = new Wma(Period);
- base.InitIndicator();
+ ma = new Wma(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"WMA {Periods}:{SourceName}";
}
diff --git a/quantower/Averages/ZlemaIndicator.cs b/quantower/Averages/ZlemaIndicator.cs
index f89c8188..5ef974ef 100644
--- a/quantower/Averages/ZlemaIndicator.cs
+++ b/quantower/Averages/ZlemaIndicator.cs
@@ -1,24 +1,58 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class ZlemaIndicator : IndicatorBase
+public class ZlemaIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 14;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Zlema? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"ZLEMA {Period} : {SourceName}";
+ protected LineSeries? Series;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public ZlemaIndicator() : base()
+ public ZlemaIndicator()
{
- Name = "ZLEMA - Zero-Lag Exponential Moving Average";
- Description = "EMA variant that reduces lag by using linear extrapolation, providing faster response to price changes.";
+ OnBackGround = true;
+ SeparateWindow = false;
+ SourceName = Source.ToString();
+ Name = "ZLEMA - Zero Lag Exponential Moving Average";
+ Description = "Zero Lag Exponential Moving Average";
+ Series = new(name: $"ZLEMA {Periods}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- base.InitIndicator();
- ma = new Zlema(Period);
+ ma = new Zlema(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"ZLEMA {Periods}:{SourceName}";
}
diff --git a/quantower/Averages/Averages.csproj b/quantower/Averages/_Averages.csproj
similarity index 89%
rename from quantower/Averages/Averages.csproj
rename to quantower/Averages/_Averages.csproj
index 692601e3..6b270b32 100644
--- a/quantower/Averages/Averages.csproj
+++ b/quantower/Averages/_Averages.csproj
@@ -1,5 +1,6 @@
+ Averages
Indicator
bin\$(Configuration)\
true
@@ -14,7 +15,8 @@
-
+
+
..\..\.github\TradingPlatform.BusinessLayer.dll
diff --git a/quantower/IndicatorExtensions.cs b/quantower/IndicatorExtensions.cs
new file mode 100644
index 00000000..9de6a9d3
--- /dev/null
+++ b/quantower/IndicatorExtensions.cs
@@ -0,0 +1,148 @@
+using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+
+namespace QuanTAlib;
+
+public enum SourceType
+{
+ Open, High, Low, Close, HL2, OC2, OHL3, HLC3, OHLC4, HLCC4
+}
+public static class IndicatorExtensions
+{
+ public static TValue GetInputValue(this Indicator indicator, UpdateArgs args, SourceType source)
+ {
+ var historicalData = indicator.HistoricalData;
+
+ TBar bar = new TBar(
+ Time: historicalData.Time(),
+ Open: historicalData[indicator.Count - 1, SeekOriginHistory.Begin][PriceType.Open],
+ High: historicalData[indicator.Count - 1, SeekOriginHistory.Begin][PriceType.High],
+ Low: historicalData[indicator.Count - 1, SeekOriginHistory.Begin][PriceType.Low],
+ Close: historicalData[indicator.Count - 1, SeekOriginHistory.Begin][PriceType.Close],
+ Volume: historicalData[indicator.Count - 1, SeekOriginHistory.Begin][PriceType.Volume],
+ IsNew: args.Reason == UpdateReason.NewBar || args.Reason == UpdateReason.HistoricalBar
+ );
+
+ double price = source switch
+ {
+ SourceType.Open => bar.Open,
+ SourceType.High => bar.High,
+ SourceType.Low => bar.Low,
+ SourceType.Close => bar.Close,
+ SourceType.HL2 => bar.HL2,
+ SourceType.OC2 => bar.OC2,
+ SourceType.OHL3 => bar.OHL3,
+ SourceType.HLC3 => bar.HLC3,
+ SourceType.OHLC4 => bar.OHLC4,
+ SourceType.HLCC4 => bar.HLCC4,
+ _ => bar.Close
+ };
+
+ return new TValue(bar.Time, price, bar.IsNew);
+ }
+
+ public static TBar GetInputBar(this Indicator indicator, UpdateArgs args)
+ {
+ var historicalData = indicator.HistoricalData;
+
+ return new TBar(
+ Time: historicalData.Time(),
+ Open: historicalData[indicator.Count - 1, SeekOriginHistory.Begin][PriceType.Open],
+ High: historicalData[indicator.Count - 1, SeekOriginHistory.Begin][PriceType.High],
+ Low: historicalData[indicator.Count - 1, SeekOriginHistory.Begin][PriceType.Low],
+ Close: historicalData[indicator.Count - 1, SeekOriginHistory.Begin][PriceType.Close],
+ Volume: historicalData[indicator.Count - 1, SeekOriginHistory.Begin][PriceType.Volume],
+ IsNew: args.Reason == UpdateReason.NewBar || args.Reason == UpdateReason.HistoricalBar
+ );
+ }
+
+#pragma warning disable CA1416 // Validate platform compatibility
+
+ public static void PaintSmoothCurve(this Indicator indicator, PaintChartEventArgs args, LineSeries series, int warmupPeriod, bool showColdValues = true, double tension = 0.2)
+ {
+ if (!series.Visible || indicator.CurrentChart == null)
+ return;
+
+ Graphics gr = args.Graphics;
+ var mainWindow = indicator.CurrentChart.MainWindow;
+ var converter = mainWindow.CoordinatesConverter;
+ var clientRect = mainWindow.ClientRectangle;
+
+ gr.SetClip(clientRect);
+ DateTime leftTime = new[] { converter.GetTime(clientRect.Left), indicator.HistoricalData.Time(indicator!.Count - 1) }.Max();
+ DateTime rightTime = new[] { converter.GetTime(clientRect.Right), indicator.HistoricalData.Time(0) }.Min();
+
+ int leftIndex = (int)indicator.HistoricalData.GetIndexByTime(leftTime.Ticks) + 1;
+ int rightIndex = (int)indicator.HistoricalData.GetIndexByTime(rightTime.Ticks);
+
+ List allPoints = new List();
+ for (int i = rightIndex; i < leftIndex; i++)
+ {
+ int barX = (int)converter.GetChartX(indicator.HistoricalData.Time(i));
+ int barY = (int)converter.GetChartY(series[i]);
+ int halfBarWidth = indicator.CurrentChart.BarsWidth / 2;
+ Point point = new Point(barX + halfBarWidth, barY);
+ allPoints.Add(point);
+ }
+
+ if (allPoints.Count > 1)
+ {
+
+ 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 })
+ {
+ int hotCount = indicator.Count - warmupPeriod - rightIndex;
+ // 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)tension);
+ }
+
+ // 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)tension);
+ }
+ }
+ }
+ }
+ public static void DrawText(this Indicator indicator, PaintChartEventArgs args, string text)
+ {
+ if (indicator.CurrentChart == null)
+ return;
+
+ Graphics gr = args.Graphics;
+ var clientRect = indicator.CurrentChart.MainWindow.ClientRectangle;
+
+ 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(Brushes.DarkBlue, textRect);
+ gr.DrawString(text, font, Brushes.White, new PointF(textRect.X + 6, textRect.Y + 5));
+ }
+
+ 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,
+ };
+ }
+
+}
+
+
+
+
diff --git a/quantower/Statistics/CurvatureIndicator.cs b/quantower/Statistics/CurvatureIndicator.cs
index 2ef393e0..4ba48c9e 100644
--- a/quantower/Statistics/CurvatureIndicator.cs
+++ b/quantower/Statistics/CurvatureIndicator.cs
@@ -1,25 +1,63 @@
+using System.Drawing;
using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class CurvatureIndicator : IndicatorBase
+public class CurvatureIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 2, 2000, 1, 0)]
- public int Period { get; set; } = 20;
+ [InputParameter("Periods", sortIndex: 1, 3, 1000, 1, 0)]
+ public int Periods { get; set; } = 20;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Curvature? curvature;
- protected override AbstractBase QuanTAlib => curvature!;
- public override string ShortName => $"CURVATURE {Period} : {SourceName}";
+ protected LineSeries? CurvatureSeries;
+ protected LineSeries? LineSeries;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods * 2 - 1;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
public CurvatureIndicator()
{
- Name = "CURVATURE - Rate of Change of Slope";
- Description = "Measures the rate of change of the slope, indicating acceleration or deceleration in price movement.";
+ Name = "Curvature";
+ Description = "Calculates the rate of change of the slope over a specified period";
SeparateWindow = true;
+ SourceName = Source.ToString();
+
+ CurvatureSeries = new("Curvature", Color.Blue, 2, LineStyle.Solid);
+ AddLineSeries(CurvatureSeries);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- curvature = new(Period);
- MinHistoryDepths = curvature.WarmupPeriod;
+ curvature = new Curvature(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = curvature!.Calc(input);
+
+ CurvatureSeries!.SetValue(result.Value);
+ if (curvature.Line.HasValue)
+ {
+ LineSeries!.SetValue(curvature.Line.Value);
+ }
+ }
+
+ public override string ShortName => $"Curvature ({Periods}:{SourceName})";
}
diff --git a/quantower/Statistics/EntropyIndicator.cs b/quantower/Statistics/EntropyIndicator.cs
index 5614c288..6dfd343b 100644
--- a/quantower/Statistics/EntropyIndicator.cs
+++ b/quantower/Statistics/EntropyIndicator.cs
@@ -1,26 +1,58 @@
+using System.Drawing;
using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class EntropyIndicator : IndicatorBase
+public class EntropyIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 2, 2000, 1, 0)]
- public int Period { get; set; } = 50;
+ [InputParameter("Periods", sortIndex: 1, 2, 1000, 1, 0)]
+ public int Periods { get; set; } = 20;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Entropy? entropy;
- protected override AbstractBase QuanTAlib => entropy!;
- public override string ShortName => $"ENTROPY {Period} : {SourceName}";
+ protected LineSeries? EntropySeries;
+ protected string? SourceName;
+ public int MinHistoryDepths => 2;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public EntropyIndicator() : base()
+ public EntropyIndicator()
{
- Name = "ENTROPY - Entropy";
- Description = "Measures the randomness or uncertainty in price movements, useful for identifying market phases.";
+ Name = "Entropy";
+ Description = "Measures the unpredictability of data using Shannon's Entropy";
SeparateWindow = true;
+ SourceName = Source.ToString();
+
+ EntropySeries = new("Entropy", Color.Blue, 2, LineStyle.Solid);
+ AddLineSeries(EntropySeries);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- entropy = new(Period);
- MinHistoryDepths = entropy.WarmupPeriod;
- base.InitIndicator();
+ entropy = new Entropy(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = entropy!.Calc(input);
+
+ EntropySeries!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"Entropy ({Periods}:{SourceName})";
}
diff --git a/quantower/Statistics/KurtosisIndicator.cs b/quantower/Statistics/KurtosisIndicator.cs
index 086bb61d..620f53dd 100644
--- a/quantower/Statistics/KurtosisIndicator.cs
+++ b/quantower/Statistics/KurtosisIndicator.cs
@@ -1,26 +1,58 @@
+using System.Drawing;
using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class KurtosisIndicator : IndicatorBase
+public class KurtosisIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 4, 2000, 1, 0)]
- public int Period { get; set; } = 20;
+ [InputParameter("Periods", sortIndex: 1, 4, 1000, 1, 0)]
+ public int Periods { get; set; } = 20;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Kurtosis? kurtosis;
- protected override AbstractBase QuanTAlib => kurtosis!;
- public override string ShortName => $"KURTOSIS {Period} : {SourceName}";
+ protected LineSeries? KurtosisSeries;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods - 1;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public KurtosisIndicator() : base()
+ public KurtosisIndicator()
{
- Name = "KURTOSIS - Relative Flatness";
- Description = "Measures the 'tailedness' of price distribution, indicating potential for extreme market movements.";
+ Name = "Kurtosis";
+ Description = "Measures the 'tailedness' of the probability distribution of a real-valued random variable";
SeparateWindow = true;
+ SourceName = Source.ToString();
+
+ KurtosisSeries = new("Kurtosis", Color.Blue, 2, LineStyle.Solid);
+ AddLineSeries(KurtosisSeries);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- kurtosis = new(Period);
- MinHistoryDepths = kurtosis.WarmupPeriod;
- base.InitIndicator();
+ kurtosis = new Kurtosis(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = kurtosis!.Calc(input);
+
+ KurtosisSeries!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"Kurtosis ({Periods}:{SourceName})";
}
diff --git a/quantower/Statistics/MaxIndicator.cs b/quantower/Statistics/MaxIndicator.cs
index b8af5012..23a67501 100644
--- a/quantower/Statistics/MaxIndicator.cs
+++ b/quantower/Statistics/MaxIndicator.cs
@@ -1,29 +1,61 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class MaxIndicator : IndicatorBase
+public class MaxIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 50;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 20;
- [InputParameter("Decay to mean", sortIndex: 1, minimum: 0.00, maximum: 100.0, increment: 0.01, decimalPlaces: 2)]
- public double Decay { get; set; } = 0.1;
+ [InputParameter("Decay", sortIndex: 2, 0, 10, 0.01, 2)]
+ public double Decay { get; set; } = 0;
+
+ [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.High;
private Max? ma;
- protected override AbstractBase QuanTAlib => ma!;
- public override string ShortName => $"MAX {Period} : {Decay:F2} : {SourceName}";
+ protected LineSeries? MaxSeries;
+ protected string? SourceName;
+ public int MinHistoryDepths => 0;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public MaxIndicator() : base()
+ public MaxIndicator()
{
- Name = "MAX - Maximum value (with decay)";
- Description = "Tracks the maximum value over a period, with a decay factor to gradually adjust to new highs.";
+ Name = "Max";
+ Description = "Calculates the maximum value over a specified period, with an optional decay factor";
+ SeparateWindow = false;
+ SourceName = Source.ToString();
+
+ MaxSeries = new("Max", Color.Blue, 2, LineStyle.Solid);
+ AddLineSeries(MaxSeries);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- ma = new Max(Period, Decay);
- MinHistoryDepths = ma.WarmupPeriod;
- Source = 2;
- base.InitIndicator();
+ ma = new Max(Periods, Decay);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ MaxSeries!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"Max ({Periods}, {Decay:F2}:{SourceName})";
}
diff --git a/quantower/Statistics/MedianIndicator.cs b/quantower/Statistics/MedianIndicator.cs
index 05d500c4..471ace45 100644
--- a/quantower/Statistics/MedianIndicator.cs
+++ b/quantower/Statistics/MedianIndicator.cs
@@ -1,24 +1,58 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class MedianIndicator : IndicatorBase
+public class MedianIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 50;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 20;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Median? med;
- protected override AbstractBase QuanTAlib => med!;
- public override string ShortName => $"MEDIAN {Period} : {SourceName}";
- public MedianIndicator() : base()
+ protected LineSeries? MedianSeries;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
+
+ public MedianIndicator()
{
- Name = "MEDIAN - Median historical value";
- Description = "Calculates the middle value of price data over a specified period, less affected by outliers than mean.";
+ Name = "Median";
+ Description = "Calculates the median value over a specified period";
+ SeparateWindow = false;
+ SourceName = Source.ToString();
+
+ MedianSeries = new("Median", Color.Blue, 2, LineStyle.Solid);
+ AddLineSeries(MedianSeries);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- med = new Median(Period);
- MinHistoryDepths = med.WarmupPeriod;
- base.InitIndicator();
+ med = new Median(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = med!.Calc(input);
+
+ MedianSeries!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"Median ({Periods}:{SourceName})";
}
diff --git a/quantower/Statistics/MinIndicator.cs b/quantower/Statistics/MinIndicator.cs
index 3399bdc7..a7fa2e59 100644
--- a/quantower/Statistics/MinIndicator.cs
+++ b/quantower/Statistics/MinIndicator.cs
@@ -1,28 +1,61 @@
-using TradingPlatform.BusinessLayer;
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class MinIndicator : IndicatorBase
+public class MinIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 50;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 20;
- [InputParameter("Decay to mean", sortIndex: 1, minimum: 0.00, maximum: 100.0, increment: 0.01, decimalPlaces: 2)]
- public double Decay { get; set; } = 0.1;
+ [InputParameter("Decay", sortIndex: 2, 0, 10, 0.01, 2)]
+ public double Decay { get; set; } = 0;
+
+ [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.Low;
private Min? mi;
- protected override AbstractBase QuanTAlib => mi!;
- public override string ShortName => $"MIN {Period} : {Decay:F2} : {SourceName}";
- public MinIndicator() : base()
+ protected LineSeries? MinSeries;
+ protected string? SourceName;
+ public int MinHistoryDepths => 0;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
+
+ public MinIndicator()
{
- Name = "MIN - Minimum value (with decay)";
- Description = "Tracks the minimum value over a period, with a decay factor to gradually adjust to new lows.";
+ Name = "Min";
+ Description = "Calculates the minimum value over a specified period, with an optional decay factor";
+ SeparateWindow = false;
+ SourceName = Source.ToString();
+
+ MinSeries = new("Min", Color.Blue, 2, LineStyle.Solid);
+ AddLineSeries(MinSeries);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- mi = new Min(Period, Decay);
- MinHistoryDepths = mi.WarmupPeriod;
- Source = 3;
- base.InitIndicator();
+ mi = new Min(Periods, Decay);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = mi!.Calc(input);
+
+ MinSeries!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"Min ({Periods}, {Decay:F2}:{SourceName})";
}
diff --git a/quantower/Statistics/ModeIndicator.cs b/quantower/Statistics/ModeIndicator.cs
index e14b17ad..7294ed2c 100644
--- a/quantower/Statistics/ModeIndicator.cs
+++ b/quantower/Statistics/ModeIndicator.cs
@@ -1,24 +1,58 @@
+using System.Drawing;
using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class ModeIndicator : IndicatorBase
+public class ModeIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 50;
+ [InputParameter("Periods", sortIndex: 1, 1, 1000, 1, 0)]
+ public int Periods { get; set; } = 20;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Mode? mode;
- protected override AbstractBase QuanTAlib => mode!;
- public override string ShortName => $"MODE {Period} : {SourceName}";
- public ModeIndicator() : base()
+ protected LineSeries? ModeSeries;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
+
+ public ModeIndicator()
{
- Name = "MODE - Most frequent historical value";
- Description = "Identifies the most frequently occurring price value over a specified period, indicating price clusters.";
+ Name = "Mode";
+ Description = "Calculates the most frequent value in a specified period";
+ SeparateWindow = false;
+ SourceName = Source.ToString();
+
+ ModeSeries = new("Mode", Color.Blue, 2, LineStyle.Solid);
+ AddLineSeries(ModeSeries);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- mode = new Mode(Period);
- MinHistoryDepths = mode.WarmupPeriod;
- base.InitIndicator();
+ mode = new Mode(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = mode!.Calc(input);
+
+ ModeSeries!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"Mode ({Periods}:{SourceName})";
}
diff --git a/quantower/Statistics/PercentileIndicator.cs b/quantower/Statistics/PercentileIndicator.cs
index 0e4a5e91..ba861496 100644
--- a/quantower/Statistics/PercentileIndicator.cs
+++ b/quantower/Statistics/PercentileIndicator.cs
@@ -1,28 +1,61 @@
+using System.Drawing;
using TradingPlatform.BusinessLayer;
-namespace QuanTAlib;
-public class PercentileIndicator : IndicatorBase
-{
- [InputParameter("Period", sortIndex: 1, 2, 2000, 1, 0)]
- public int Period { get; set; } = 20;
- [InputParameter("Percent", sortIndex: 2, 0, 100, 1, 0)]
- public double Percent { get; set; } = 50;
+namespace QuanTAlib;
+
+public class PercentileIndicator : Indicator, IWatchlistIndicator
+{
+ [InputParameter("Periods", sortIndex: 1, 2, 1000, 1, 0)]
+ public int Periods { get; set; } = 20;
+
+ [InputParameter("Percentile", sortIndex: 2, 0, 100, 0.1, 1)]
+ public double PercentileValue { get; set; } = 50;
+
+ [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;
private Percentile? percentile;
- protected override AbstractBase QuanTAlib => percentile!;
- public override string ShortName => $"PERCENTILE {Period} {Percent:F0}% : {SourceName}";
+ protected LineSeries? PercentileSeries;
+ protected string? SourceName;
+ public int MinHistoryDepths => 2;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public PercentileIndicator() : base()
+ public PercentileIndicator()
{
- Name = "PERCENTILE - n-th Percentile";
- Description = "Calculates the value below which a given percentage of observations falls within a specified period.";
+ Name = "Percentile";
+ Description = "Calculates the value at a specified percentile in a given period of data points";
SeparateWindow = false;
+ SourceName = Source.ToString();
+
+ PercentileSeries = new("Percentile", Color.Blue, 2, LineStyle.Solid);
+ AddLineSeries(PercentileSeries);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- percentile = new(Period, Percent);
- MinHistoryDepths = percentile.WarmupPeriod;
- base.InitIndicator();
+ percentile = new Percentile(Periods, PercentileValue);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = percentile!.Calc(input);
+
+ PercentileSeries!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"Percentile ({Periods}, {PercentileValue}%:{SourceName})";
}
diff --git a/quantower/Statistics/SkewIndicator.cs b/quantower/Statistics/SkewIndicator.cs
index 7cf67cb9..6f684970 100644
--- a/quantower/Statistics/SkewIndicator.cs
+++ b/quantower/Statistics/SkewIndicator.cs
@@ -1,26 +1,58 @@
+using System.Drawing;
using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class SkewIndicator : IndicatorBase
+public class SkewIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 3, 2000, 1, 0)]
- public int Period { get; set; } = 20;
+ [InputParameter("Periods", sortIndex: 1, 3, 1000, 1, 0)]
+ public int Periods { get; set; } = 20;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Skew? skew;
- protected override AbstractBase QuanTAlib => skew!;
- public override string ShortName => $"SKEW {Period} : {SourceName}";
+ protected LineSeries? SkewSeries;
+ protected string? SourceName;
+ public int MinHistoryDepths => 3;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public SkewIndicator() : base()
+ public SkewIndicator()
{
- Name = "SKEW - Skewness";
- Description = "Measures the asymmetry of price distribution, indicating potential trend direction or reversal.";
+ Name = "Skew";
+ Description = "Measures the asymmetry of the probability distribution of a real-valued random variable about its mean";
SeparateWindow = true;
+ SourceName = Source.ToString();
+
+ SkewSeries = new("Skew", Color.Blue, 2, LineStyle.Solid);
+ AddLineSeries(SkewSeries);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- skew = new(Period);
- MinHistoryDepths = skew.WarmupPeriod;
- base.InitIndicator();
+ skew = new Skew(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = skew!.Calc(input);
+
+ SkewSeries!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"Skew ({Periods}:{SourceName})";
}
diff --git a/quantower/Statistics/SlopeIndicator.cs b/quantower/Statistics/SlopeIndicator.cs
index 7d6b65db..c5d32741 100644
--- a/quantower/Statistics/SlopeIndicator.cs
+++ b/quantower/Statistics/SlopeIndicator.cs
@@ -1,25 +1,82 @@
+using System.Drawing;
using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class SlopeIndicator : IndicatorBase
+public class SlopeIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 2, 2000, 1, 0)]
- public int Period { get; set; } = 20;
+ [InputParameter("Periods", sortIndex: 1, 2, 1000, 1, 0)]
+ public int Periods { get; set; } = 20;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Slope? slope;
- protected override AbstractBase QuanTAlib => slope!;
- public override string ShortName => $"SLOPE {Period} : {SourceName}";
+ protected LineSeries? SlopeSeries;
+ protected LineSeries? LineSeries;
+ protected string? SourceName;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
public SlopeIndicator()
{
- Name = "SLOPE - Trend Slope";
- Description = "Measures the rate of change in price over a specified period, indicating trend strength and direction.";
+ Name = "Slope";
+ Description = "Calculates the slope of a linear regression line for the specified period";
SeparateWindow = true;
+ SourceName = Source.ToString();
+
+ SlopeSeries = new("Slope", Color.Blue, 2, LineStyle.Solid);
+ LineSeries = new("Regression Line", Color.Red, 1, LineStyle.Solid);
+ AddLineSeries(SlopeSeries);
+ AddLineSeries(LineSeries);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- slope = new(Period);
- MinHistoryDepths = slope.WarmupPeriod;
+ slope = new Slope(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
+ }
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = slope!.Calc(input);
+
+ SlopeSeries!.SetValue(result.Value);
+ if (slope.Line.HasValue)
+ {
+ LineSeries!.SetValue(slope.Line.Value);
+ }
+ }
+
+ public override string ShortName
+ {
+ get
+ {
+ var result = $"Slope ({Periods}:{SourceName})";
+ if (slope != null)
+ {
+ result += $" Slope: {Math.Round(SlopeSeries!.GetValue(), 6)}";
+ if (slope.Line.HasValue)
+ result += $", Line: {Math.Round(slope.Line.Value, 6)}";
+ if (slope.Intercept.HasValue)
+ result += $", Intercept: {Math.Round(slope.Intercept.Value, 6)}";
+ if (slope.RSquared.HasValue)
+ result += $", R²: {Math.Round(slope.RSquared.Value, 6)}";
+ }
+ return result;
+ }
}
}
diff --git a/quantower/Statistics/StddevIndicator.cs b/quantower/Statistics/StddevIndicator.cs
index 6be198f9..0c1b557c 100644
--- a/quantower/Statistics/StddevIndicator.cs
+++ b/quantower/Statistics/StddevIndicator.cs
@@ -1,28 +1,61 @@
+using System.Drawing;
using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class StddevIndicator : IndicatorBase
+public class StddevIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 20;
+ [InputParameter("Periods", sortIndex: 1, 2, 1000, 1, 0)]
+ public int Periods { get; set; } = 20;
[InputParameter("Population", sortIndex: 2)]
public bool IsPopulation { 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;
+
private Stddev? stddev;
- protected override AbstractBase QuanTAlib => stddev!;
- public override string ShortName => $"STDDEV {Period} : {SourceName}";
- public StddevIndicator() : base()
+ protected LineSeries? StddevSeries;
+ protected string? SourceName;
+ public int MinHistoryDepths => 2;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
+
+ public StddevIndicator()
{
- Name = "STDDEV - Standard Deviation";
- Description = "Measures price volatility by calculating the dispersion of prices from their average over a period.";
+ Name = "Standard Deviation";
+ Description = "Measures the amount of variation or dispersion of a set of values";
SeparateWindow = true;
+ SourceName = Source.ToString();
+
+ StddevSeries = new("StdDev", Color.Blue, 2, LineStyle.Solid);
+ AddLineSeries(StddevSeries);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- stddev = new(Period, IsPopulation);
- MinHistoryDepths = stddev.WarmupPeriod;
- base.InitIndicator();
+ stddev = new Stddev(Periods, IsPopulation);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = stddev!.Calc(input);
+
+ StddevSeries!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"StdDev ({Periods}, {(IsPopulation ? "Pop" : "Sample")}:{SourceName})";
}
diff --git a/quantower/Statistics/VarianceIndicator.cs b/quantower/Statistics/VarianceIndicator.cs
index d55552ad..9f0b5234 100644
--- a/quantower/Statistics/VarianceIndicator.cs
+++ b/quantower/Statistics/VarianceIndicator.cs
@@ -1,29 +1,61 @@
+using System.Drawing;
using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class VarianceIndicator : IndicatorBase
+public class VarianceIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, minimum: 2, maximum: 2000, increment: 1, decimalPlaces: 0)]
- public int Period { get; set; } = 20;
+ [InputParameter("Periods", sortIndex: 1, 2, 1000, 1, 0)]
+ public int Periods { get; set; } = 20;
[InputParameter("Population", sortIndex: 2)]
public bool IsPopulation { 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;
+
private Variance? variance;
- protected override AbstractBase QuanTAlib => variance!;
- public override string ShortName => $"VAR {Period} : {SourceName}";
- public VarianceIndicator() : base()
+ protected LineSeries? VarianceSeries;
+ protected string? SourceName;
+ public int MinHistoryDepths => 2;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
+
+ public VarianceIndicator()
{
- Name = "VAR - Variance";
- Description = "Measures the spread of price data around its mean, indicating volatility and potential trend changes.";
+ Name = "Variance";
+ Description = "Measures the spread of a set of numbers from their average value";
SeparateWindow = true;
+ SourceName = Source.ToString();
+
+ VarianceSeries = new("Variance", Color.Blue, 2, LineStyle.Solid);
+ AddLineSeries(VarianceSeries);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- SeparateWindow = true;
- variance = new(Period, IsPopulation);
- MinHistoryDepths = variance.WarmupPeriod;
- base.InitIndicator();
+ variance = new Variance(Periods, IsPopulation);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = variance!.Calc(input);
+
+ VarianceSeries!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"Variance ({Periods}, {(IsPopulation ? "Pop" : "Sample")}:{SourceName})";
}
diff --git a/quantower/Statistics/ZscoreIndicator.cs b/quantower/Statistics/ZscoreIndicator.cs
index f9840d62..e708d54b 100644
--- a/quantower/Statistics/ZscoreIndicator.cs
+++ b/quantower/Statistics/ZscoreIndicator.cs
@@ -1,26 +1,58 @@
+using System.Drawing;
using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class ZScoreIndicator : IndicatorBase
+public class ZscoreIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 2, 2000, 1, 0)]
- public int Period { get; set; } = 20;
+ [InputParameter("Periods", sortIndex: 1, 2, 2000, 1, 0)]
+ public int Periods { get; set; } = 20;
+
+ [InputParameter("Data source", sortIndex: 2, 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 Zscore? zScore;
- protected override AbstractBase QuanTAlib => zScore!;
- public override string ShortName => $"ZSCORE {Period} : {SourceName}";
+ protected LineSeries? ZscoreSeries;
+ protected string? SourceName;
+ public int MinHistoryDepths => 2;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public ZScoreIndicator() : base()
+ public ZscoreIndicator()
{
- Name = "ZSCORE - Standard Score";
+ Name = "Z-Score";
Description = "Measures how many standard deviations a price is from the mean, indicating overbought/oversold levels.";
SeparateWindow = true;
+ SourceName = Source.ToString();
+
+ ZscoreSeries = new("Z-Score", Color.Blue, 2, LineStyle.Solid);
+ AddLineSeries(ZscoreSeries);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- zScore = new(Period);
- MinHistoryDepths = zScore.WarmupPeriod;
- base.InitIndicator();
+ zScore = new Zscore(Periods);
+ SourceName = Source.ToString();
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = zScore!.Calc(input);
+
+ ZscoreSeries!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"Z-Score ({Periods}:{SourceName})";
}
diff --git a/quantower/Statistics/Statistics.csproj b/quantower/Statistics/_Statistics.csproj
similarity index 89%
rename from quantower/Statistics/Statistics.csproj
rename to quantower/Statistics/_Statistics.csproj
index 402cf09d..0652872a 100644
--- a/quantower/Statistics/Statistics.csproj
+++ b/quantower/Statistics/_Statistics.csproj
@@ -1,5 +1,6 @@
+ Statistics
Indicator
bin\$(Configuration)\
true
@@ -14,7 +15,7 @@
-
+
..\..\.github\TradingPlatform.BusinessLayer.dll
diff --git a/quantower/Volatility/AtrIndicator.cs b/quantower/Volatility/AtrIndicator.cs
index 1d79ffff..fb2667ad 100644
--- a/quantower/Volatility/AtrIndicator.cs
+++ b/quantower/Volatility/AtrIndicator.cs
@@ -1,24 +1,41 @@
+using System.Drawing;
using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class AtrIndicator : IndicatorBarBase
+public class AtrIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 20;
+ [InputParameter("Periods", sortIndex: 1, 1, 2000, 1, 0)]
+ public int Periods { get; set; } = 20;
private Atr? atr;
- protected override AbstractBase QuanTAlib => atr!;
- public override string ShortName => $"ATR {Period}";
+ protected LineSeries? AtrSeries;
+ public int MinHistoryDepths => 2;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
+
public AtrIndicator()
{
Name = "ATR - Average True Range";
Description = "Measures market volatility by calculating the average range between high and low prices.";
SeparateWindow = true;
+
+ AtrSeries = new("ATR", Color.Blue, 2, LineStyle.Solid);
+ AddLineSeries(AtrSeries);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- atr = new(Period);
- MinHistoryDepths = atr!.WarmupPeriod;
+ atr = new Atr(Periods);
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TBar input = IndicatorExtensions.GetInputBar(this, args);
+ TValue result = atr!.Calc(input);
+
+ AtrSeries!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"ATR ({Periods})";
}
diff --git a/quantower/Volatility/HistoricalIndicator.cs b/quantower/Volatility/HistoricalIndicator.cs
index 8465714f..06ed5ec8 100644
--- a/quantower/Volatility/HistoricalIndicator.cs
+++ b/quantower/Volatility/HistoricalIndicator.cs
@@ -1,29 +1,44 @@
+using System.Drawing;
using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class HistoricalIndicator : IndicatorBase
+public class HistoricalIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 20;
+ [InputParameter("Periods", sortIndex: 1, 1, 2000, 1, 0)]
+ public int Periods { get; set; } = 20;
[InputParameter("Annualized", sortIndex: 2)]
public bool IsAnnualized { get; set; } = true;
private Historical? historical;
- protected override AbstractBase QuanTAlib => historical!;
- public override string ShortName => $"Historical Volatility {Period}{(IsAnnualized ? " - Annualized" : "")} : {SourceName}";
+ protected LineSeries? HvSeries;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public HistoricalIndicator() : base()
+ public HistoricalIndicator()
{
Name = "HV - Historical Volatility";
Description = "Measures price fluctuations over time, indicating market volatility based on past price movements.";
SeparateWindow = true;
+
+ HvSeries = new("HV", Color.Blue, 2, LineStyle.Solid);
+ AddLineSeries(HvSeries);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- historical = new(Period, IsAnnualized);
- MinHistoryDepths = historical.WarmupPeriod;
- base.InitIndicator();
+ historical = new Historical(Periods, IsAnnualized);
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TBar input = IndicatorExtensions.GetInputBar(this, args);
+ TValue result = historical!.Calc(input);
+
+ HvSeries!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"HV ({Periods}{(IsAnnualized ? " - Annualized" : "")})";
}
diff --git a/quantower/Volatility/RealizedIndicator.cs b/quantower/Volatility/RealizedIndicator.cs
index 86d7e000..126658c7 100644
--- a/quantower/Volatility/RealizedIndicator.cs
+++ b/quantower/Volatility/RealizedIndicator.cs
@@ -1,29 +1,44 @@
+using System.Drawing;
using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class RealizedIndicator : IndicatorBase
+public class RealizedIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
- public int Period { get; set; } = 20;
+ [InputParameter("Periods", sortIndex: 1, 1, 2000, 1, 0)]
+ public int Periods { get; set; } = 20;
[InputParameter("Annualized", sortIndex: 2)]
public bool IsAnnualized { get; set; } = true;
private Realized? realized;
- protected override AbstractBase QuanTAlib => realized!;
- public override string ShortName => $"Realized Volatility {Period}{(IsAnnualized ? " - Annualized" : "")} : {SourceName}";
+ protected LineSeries? RvSeries;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public RealizedIndicator() : base()
+ public RealizedIndicator()
{
Name = "RV - Realized Volatility";
Description = "Measures actual price volatility over a specific period, useful for risk assessment and forecasting.";
SeparateWindow = true;
+
+ RvSeries = new("RV", Color.Blue, 2, LineStyle.Solid);
+ AddLineSeries(RvSeries);
}
- protected override void InitIndicator()
+ protected override void OnInit()
{
- realized = new(Period, IsAnnualized);
- MinHistoryDepths = realized.WarmupPeriod;
- base.InitIndicator();
+ realized = new Realized(Periods, IsAnnualized);
+ base.OnInit();
}
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TBar input = IndicatorExtensions.GetInputBar(this, args);
+ TValue result = realized!.Calc(input);
+
+ RvSeries!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"RV ({Periods}{(IsAnnualized ? " - Annualized" : "")})";
}
diff --git a/quantower/Volatility/RviIndicator.cs b/quantower/Volatility/RviIndicator.cs
index 9c8de27d..005ae679 100644
--- a/quantower/Volatility/RviIndicator.cs
+++ b/quantower/Volatility/RviIndicator.cs
@@ -1,26 +1,41 @@
+using System.Drawing;
using TradingPlatform.BusinessLayer;
+
namespace QuanTAlib;
-public class RviIndicator : IndicatorBase
+public class RviIndicator : Indicator, IWatchlistIndicator
{
- [InputParameter("Period", sortIndex: 1, 2, 100, 1, 0)]
- public int Period { get; set; } = 10;
+ [InputParameter("Periods", sortIndex: 1, 2, 100, 1, 0)]
+ public int Periods { get; set; } = 10;
private Rvi? rvi;
- protected override AbstractBase QuanTAlib => rvi!;
- public override string ShortName => $"RVI {Period} : {SourceName}";
+ protected LineSeries? RviSeries;
+ public int MinHistoryDepths => Periods;
+ int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
- public RviIndicator() : base()
+ public RviIndicator()
{
Name = "RVI - Relative Volatility Index";
Description = "Measures the direction of volatility, helping to identify overbought or oversold conditions in price.";
SeparateWindow = true;
- }
- protected override void InitIndicator()
- {
- rvi = new Rvi(Period);
- MinHistoryDepths = rvi.WarmupPeriod;
- base.InitIndicator();
+ RviSeries = new("RVI", Color.Blue, 2, LineStyle.Solid);
+ AddLineSeries(RviSeries);
}
+
+ protected override void OnInit()
+ {
+ rvi = new Rvi(Periods);
+ base.OnInit();
+ }
+
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TBar input = IndicatorExtensions.GetInputBar(this, args);
+ TValue result = rvi!.Calc(input);
+
+ RviSeries!.SetValue(result.Value);
+ }
+
+ public override string ShortName => $"RVI ({Periods})";
}
diff --git a/quantower/Volatility/TestIndicator.cs b/quantower/Volatility/TestIndicator.cs
new file mode 100644
index 00000000..aad1dfda
--- /dev/null
+++ b/quantower/Volatility/TestIndicator.cs
@@ -0,0 +1,66 @@
+using System.Drawing;
+using TradingPlatform.BusinessLayer;
+
+namespace QuanTAlib;
+
+public class TestIndicator : Indicator, IWatchlistIndicator
+{
+ [InputParameter("Period", sortIndex: 1, 1, 2000, 1, 0)]
+ public int Period { get; set; } = 10;
+
+ [InputParameter("Data source", sortIndex: 20, 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 Sma? ma;
+ protected LineSeries? Series;
+ //protected string? SourceName;
+ public int MinHistoryDepths { get; set; }
+ int IWatchlistIndicator.MinHistoryDepths => 0; //QuanTAlib indicators generate value immediately
+
+
+ public TestIndicator()
+ {
+ OnBackGround = true;
+ SeparateWindow = false;
+ Name = "TEST";
+ Description = "test and test and test and more test.";
+ Series = new(name: $"{Name}", color: Color.Yellow, width: 2, style: LineStyle.Solid);
+ AddLineSeries(Series);
+ }
+
+ protected override void OnInit()
+ {
+ ma = new Sma(Period);
+ base.OnInit();
+ }
+ protected override void OnUpdate(UpdateArgs args)
+ {
+ TValue input = this.GetInputValue(args, Source);
+ TValue result = ma!.Calc(input);
+
+ Series!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here
+ Series!.SetValue(result);
+ }
+
+ public override void OnPaintChart(PaintChartEventArgs args)
+ {
+ base.OnPaintChart(args);
+ this.PaintSmoothCurve(args, Series!, ma!.WarmupPeriod, ShowColdValues, tension: 0.2);
+ this.DrawText(args, Description);
+ }
+}
+
diff --git a/quantower/Volatility/Volatility.csproj b/quantower/Volatility/_Volatility.csproj
similarity index 89%
rename from quantower/Volatility/Volatility.csproj
rename to quantower/Volatility/_Volatility.csproj
index 3b829bd6..4edad8ee 100644
--- a/quantower/Volatility/Volatility.csproj
+++ b/quantower/Volatility/_Volatility.csproj
@@ -1,5 +1,6 @@
+ Volatility
Indicator
bin\$(Configuration)\
true
@@ -14,7 +15,8 @@
-
+
+
..\..\.github\TradingPlatform.BusinessLayer.dll
diff --git a/quantower/_IndicatorBarBase.cs b/quantower/_IndicatorBarBase.cs
deleted file mode 100644
index 47bbcc1b..00000000
--- a/quantower/_IndicatorBarBase.cs
+++ /dev/null
@@ -1,135 +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 AbstractBase 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 allPoints = new List();
- 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(barX + halfBarWidth, barY);
- allPoints.Add(point);
- }
-
- if (allPoints.Count > 1)
- {
- DrawSmoothCombinedCurve(gr, allPoints, this.Count - QuanTAlib.WarmupPeriod - rightIndex);
- }
- }
-
- private void DrawSmoothCombinedCurve(Graphics gr, List 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("Inter", 8);
- SizeF textSize = gr.MeasureString(text, font);
- RectangleF textRect = new(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));
- }
-}
\ No newline at end of file
diff --git a/quantower/_IndicatorBase.cs b/quantower/_IndicatorBase.cs
deleted file mode 100644
index 37d70d06..00000000
--- a/quantower/_IndicatorBase.cs
+++ /dev/null
@@ -1,188 +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.Yellow, width: 2, style: LineStyle.Solid);
-
- AddLineSeries(Series);
- }
-
- protected virtual void InitIndicator()
- {
- SourceName = GetName(Source);
- }
-
- 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);
-
- 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 allPoints = new List();
- 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 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.2);
- }
-
- // 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.2);
- }
- }
- }
- private 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 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 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"
- };
- }
-
-}
\ No newline at end of file