mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-22 04:28:04 +00:00
Add Fisher Transform indicator
--- For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/mihakralj/QuanTAlib?shareId=XXXX-XXXX-XXXX-XXXX).
This commit is contained in:
@@ -321,4 +321,19 @@ public class OscillatorsUpdateTests
|
|||||||
|
|
||||||
Assert.Equal(initialValue, finalValue, precision);
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Fisher_Update()
|
||||||
|
{
|
||||||
|
var indicator = new Fisher(period: 10);
|
||||||
|
double initialValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: true));
|
||||||
|
|
||||||
|
for (int i = 0; i < RandomUpdates; i++)
|
||||||
|
{
|
||||||
|
indicator.Calc(new TValue(DateTime.Now, GetRandomDouble(), IsNew: false));
|
||||||
|
}
|
||||||
|
double finalValue = indicator.Calc(new TValue(DateTime.Now, ReferenceValue, IsNew: false));
|
||||||
|
|
||||||
|
Assert.Equal(initialValue, finalValue, precision);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
namespace QuanTAlib;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// FISHER: Fisher Transform
|
||||||
|
/// A technical indicator that converts prices into a Gaussian normal distribution.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The Fisher Transform calculation process:
|
||||||
|
/// 1. Calculate the value of the price relative to its high-low range.
|
||||||
|
/// 2. Apply the Fisher Transform formula to the normalized price.
|
||||||
|
/// 3. Smooth the result using an exponential moving average.
|
||||||
|
///
|
||||||
|
/// Key characteristics:
|
||||||
|
/// - Oscillates between -1 and 1
|
||||||
|
/// - Emphasizes price reversals
|
||||||
|
/// - Can be used to identify overbought and oversold conditions
|
||||||
|
///
|
||||||
|
/// Formula:
|
||||||
|
/// Fisher Transform = 0.5 * log((1 + x) / (1 - x))
|
||||||
|
/// where:
|
||||||
|
/// x = 2 * ((price - min) / (max - min) - 0.5)
|
||||||
|
///
|
||||||
|
/// Sources:
|
||||||
|
/// John F. Ehlers - "Rocket Science for Traders" (2001)
|
||||||
|
/// https://www.investopedia.com/terms/f/fisher-transform.asp
|
||||||
|
/// </remarks>
|
||||||
|
[SkipLocalsInit]
|
||||||
|
public sealed class Fisher : AbstractBase
|
||||||
|
{
|
||||||
|
private readonly int _period;
|
||||||
|
private readonly double[] _prices;
|
||||||
|
private double _prevFisher;
|
||||||
|
private double _prevValue;
|
||||||
|
|
||||||
|
/// <param name="source">The data source object that publishes updates.</param>
|
||||||
|
/// <param name="period">The calculation period (default: 10)</param>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Fisher(object source, int period = 10) : this(period)
|
||||||
|
{
|
||||||
|
var pubEvent = source.GetType().GetEvent("Pub");
|
||||||
|
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Fisher(int period = 10)
|
||||||
|
{
|
||||||
|
_period = period;
|
||||||
|
_prices = new double[period];
|
||||||
|
WarmupPeriod = period;
|
||||||
|
Name = "FISHER";
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
protected override void ManageState(bool isNew)
|
||||||
|
{
|
||||||
|
if (isNew)
|
||||||
|
{
|
||||||
|
_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private double NormalizePrice(double price, double min, double max)
|
||||||
|
{
|
||||||
|
return 2 * ((price - min) / (max - min) - 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private double FisherTransform(double value)
|
||||||
|
{
|
||||||
|
return 0.5 * System.Math.Log((1 + value) / (1 - value));
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
protected override double Calculation()
|
||||||
|
{
|
||||||
|
ManageState(Input.IsNew);
|
||||||
|
|
||||||
|
var idx = _index % _period;
|
||||||
|
_prices[idx] = Input.Value;
|
||||||
|
|
||||||
|
if (_index < _period - 1) return double.NaN;
|
||||||
|
|
||||||
|
var min = _prices.Min();
|
||||||
|
var max = _prices.Max();
|
||||||
|
var normalizedPrice = NormalizePrice(Input.Value, min, max);
|
||||||
|
var fisherValue = FisherTransform(normalizedPrice);
|
||||||
|
|
||||||
|
var smoothedFisher = 0.5 * (fisherValue + _prevFisher);
|
||||||
|
_prevFisher = smoothedFisher;
|
||||||
|
|
||||||
|
return smoothedFisher;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# Oscillators indicators
|
# Oscillators indicators
|
||||||
Done: 21, Todo: 8
|
Done: 22, Todo: 7
|
||||||
|
|
||||||
✔️ AC - Acceleration Oscillator
|
✔️ AC - Acceleration Oscillator
|
||||||
✔️ AO - Awesome Oscillator
|
✔️ AO - Awesome Oscillator
|
||||||
@@ -15,7 +15,7 @@ Done: 21, Todo: 8
|
|||||||
CTI - Ehler's Correlation Trend Indicator
|
CTI - Ehler's Correlation Trend Indicator
|
||||||
✔️ DOSC - Derivative Oscillator
|
✔️ DOSC - Derivative Oscillator
|
||||||
EFI - Elder Ray's Force Index
|
EFI - Elder Ray's Force Index
|
||||||
FISHER - Fisher Transform
|
✔️ FISHER - Fisher Transform
|
||||||
FOSC - Forecast Oscillator
|
FOSC - Forecast Oscillator
|
||||||
*GATOR - Williams Alliator Oscillator (Upper Jaw, Lower Jaw, Teeth)
|
*GATOR - Williams Alliator Oscillator (Upper Jaw, Lower Jaw, Teeth)
|
||||||
*KDJ - KDJ Indicator (K, D, J lines)
|
*KDJ - KDJ Indicator (K, D, J lines)
|
||||||
|
|||||||
Reference in New Issue
Block a user