Grumson.Utilities.Taapi.Signals 1.0.8

dotnet add package Grumson.Utilities.Taapi.Signals --version 1.0.8                
NuGet\Install-Package Grumson.Utilities.Taapi.Signals -Version 1.0.8                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Grumson.Utilities.Taapi.Signals" Version="1.0.8" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Grumson.Utilities.Taapi.Signals --version 1.0.8                
#r "nuget: Grumson.Utilities.Taapi.Signals, 1.0.8"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Grumson.Utilities.Taapi.Signals as a Cake Addin
#addin nuget:?package=Grumson.Utilities.Taapi.Signals&version=1.0.8

// Install Grumson.Utilities.Taapi.Signals as a Cake Tool
#tool nuget:?package=Grumson.Utilities.Taapi.Signals&version=1.0.8                

Taapi Signals

Table of Contents

  1. Introduction
  2. Features
  3. Installation
  4. Usage
  5. Examples
  6. Contributing
  7. License
  8. Support
  9. Changelog

Introduction

The Taapi Signals Library is a powerful C# library designed for building and managing trading signals using Finite State Machines (FSM). This library integrates seamlessly with the Taapi.io API, allowing users to leverage a wide range of trading indicators for creating custom trading strategies.

With the Taapi Signals Library, developers can create robust and flexible trading systems by defining states, transitions, and conditions based on indicator values. The library provides a structured framework for automating trading workflows, making it an essential tool for algorithmic trading solutions.

Key Concepts

  1. Signals as Finite State Machines (FSM): Each trading signal is represented as an FSM, consisting of multiple states and transitions.
  2. Indicator Integration: Leverage a variety of trading indicators from Taapi.io to define conditions for state transitions.
  3. Customizable Conditions: Define indicator-based or event-driven conditions to trigger state changes.
  4. Logging: Comprehensive logging is built-in for easy debugging and monitoring.

Use Cases

  • Algorithmic Trading: Automate trading strategies by defining complex signal logic.
  • Backtesting: Simulate trading signals using historical data for strategy optimization.
  • Real-time Monitoring: Continuously evaluate market conditions and transition between signal states accordingly.

The Taapi Signals Library simplifies the process of creating sophisticated trading signals while ensuring clarity and maintainability of the trading logic.


Features

  • Finite State Machine Framework: Create, manage, and execute trading signals as FSMs.
  • Seamless Integration with Taapi.io: Utilize Taapi.io's rich set of indicators directly within your signal logic.
  • Flexible State Management: Define multiple states (e.g., Idle, TradeLong, TradeShort) and transitions for complex workflows.
  • Stop Loss Management: Set stop loss values for each state of FSM to manage risk effectively. Stop loss can be calculated based on the indicator value, or it can be a static values.
  • Condition-Based Transitions: Support for indicator-driven and event-driven conditions for state changes.
  • Event Handling: Subscribe to events for monitoring signal transitions, state changes, indicator values, stop loss values, etc.
  • Extensibility: Easily extend the library with custom conditions, actions, or states.
  • Comprehensive Logging: Built-in logging capabilities for monitoring and debugging signals.
  • Support for Backtesting: Evaluate signals using historical data to optimize strategies.
  • Real-Time Execution: Monitor live market conditions and execute signals in real time.

The library is designed to provide flexibility and ease of use, making it suitable for both beginners and advanced developers in algorithmic trading.


Installation

To install the Taapi Signals Library, follow these steps:

Prerequisites

  • .NET 9.0 or higher: Ensure you have .NET SDK installed. You can download it from Microsoft's official site.
  • Taapi.io API Key: Sign up at Taapi.io and obtain an API key for accessing indicators. Free version of the API key will probably not work, because of the limitations of the free version of the API key.

Installation Steps

Add the library to your .NET project using one of the following methods:


// .NET CLI
> dotnet add package Grumson.Utilities.Taapi.Signals --version x.x.x

// Package Manager
PM> NuGet\Install-Package Grumson.Utilities.Taapi.Signals -Version x.x.x

// Package Reference
<PackageReference Include="Grumson.Utilities.Taapi.Signals" Version="x.x.x" />

Or, include the project in your solution and reference it directly.

You're now ready to start using the Taapi Signals Library in your projects!


Usage

This section provides an examples of how to use the Taapi Signals Library to create and manage trading signals.

Basic Examples

  1. Initialize the Logger, Signal Manager and Taapi Client

    ILoggerFactory loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
    ILogger<TaapiClient> taapiLogger = loggerFactory.CreateLogger<TaapiClient>();
    
    // Initialize taaapi client
    var taapiClient = new TaapiClient(taapiLogger, taapi_api_key, subscriptionType);
    
    // Initialize signal manager
    var signalManager = new SignalManager(loggerFactory, taapiClient);
    
  2. Create a New Signal

    SignalModel signalModel = new SignalModel {
        Name = "SignalTest_Strategy",
        Description = "Description of the signal"
    };
    
  3. Add Indicators to the Signal

    var rsiIndicator = new IndicatorModel {
        Name = "RsiCondition",
        IndicatorRequest = new IndicatorRequest {
            Exchange = "binance",
            Symbol = "BTC/USDT",
            Interval = "5m",
            Indicator = "rsi",
            AdditionalParameters = new Dictionary<string, string> { { "period", "15" } }
        }
    };
    signalModel.Indicators.Add(rsiIndicator);
    
  4. Define Signal States

    var startState = new SignalState { Name = "Start", IsInitial = true };
    var idleState = new SignalState { Name = "Idle" };
    signalModel.States.Add(startState);
    signalModel.States.Add(idleState);
    
  5. Create Indicator Conditions with static threshold

    
    // Simple RSI condition: RSI > 70
    var rsiCondition = new IndicatorCondition {
        IndicatorModel = rsiIndicator,
        SubValueKey = "value",
        ConditionOperator = ConditionOperator.GreaterThan,
        Threshold = 70
    };
    
    // Wrapper for indicator condition
    var rsiConditionWrapper = new IndicatorConditionWrapper(rsiCondition, loggerFactory.CreateLogger<IndicatorConditionWrapper>());
    
  6. Create Indicator Conditions with dynamic threshold

    // RSI condition with dynamic threshold from RSI indicator -> ( CONDITION: 5 MIN RSI > 1 HOUR RSI )
    var rsiConditionDynamicThreshold = new IndicatorCondition {
        IndicatorModel = IndicatorRsiCondition,
        SubValueKey = "value",
        ConditionOperator = ConditionOperator.GreaterThan,
        //Threshold = 0m,
        IsDynamicThreshold = true, // Dynamic threshold based on the indicator value
        ThresholdIndicator = IndicatorRsiThreshold, // Indicator for dynamic threshold,
        ThresholdSubValueKey = "value" // Sub value key for dynamic threshold
    };
    
    // Wrappers for indicator conditions
    var rsiConditionDynamicThresholdWrapper = new IndicatorConditionWrapper(rsiConditionDynamicThreshold, loggerFactory.CreateLogger<IndicatorConditionWrapper>());
    
  7. Create Composite Conditions with AND/OR Logic

    // Composite condition: with AND logic
    var compositeCondition = new CompositeCondition(loggerFactory.CreateLogger<CompositeCondition>()) {
        LogicOperator = LogicOperator.And, // AND or OR logic selection
        Conditions = new List<BaseCondition> { rsiConditionWrapper, rsiConditionDynamicThresholdWrapper }
    };
    
  8. Create Event Driven Conditions

    // Event driven condition for price crossed above specific value
    var priceCrossedCondition = new EventDrivenCondition {
        EventName = "PriceCrossed", // Ime dogodka
        Predicate = parameters => (decimal)parameters["Price"] > 50 // Predicate to check if the condition is met, (if )
    };
    
    // Event driven condition for button pressed
    var buttonPressedCondition = new EventDrivenCondition {
        EventName = "ButtonPressed", // Name of the event
        Predicate = _ => true // Predicate to check if the condition is met, for button press it is always true
    };
    
  9. Add Transitions with Conditions

    var transition = new StateTransition {
        Name = "StartToIdle",
        FromState = startState,
        ToState = idleState,
        Conditions = new List<BaseCondition> { compositeCondition } // Conditions from indicators
        EventDrivenConditions = new List<EventDrivenCondition> {  buttonPressedCondition, buttonPressedCondition } // Event driven conditions
    };
    signalModel.Transitions.Add(transition);
    
  10. Validate and Save the Signal

    try {
        // Save signal model to the signal manager,
        // method will first validate the model and throw exception if model is not valid
        signalModel.Id = await signalManager.CreateSignal(signalModel);
    }
    catch (ArgumentException ex) {
        Console.WriteLine($"Argument Exception: {ex.Message}");
        return;
    }
    catch (InvalidOperationException ex) {
        Console.WriteLine($"Invalid Operation Exception: {ex.Message}");
        return;
    }
    catch (Exception ex) {
        Console.WriteLine($"Error: {ex.Message}");
        return;
    }
    
  11. Start Fetching the Signal

    signalManager.StartAutoFetching(signalId, TimeSpan.FromMinutes(1));
    
  12. Subscribe to Events

    signalManager.SubscribeToEvents(signalId,
        beforeTransition: (service, transition) => Console.WriteLine($"Before transitioning: {transition.Name}"),
        afterTransition: (service, transition) => Console.WriteLine($"After transitioning: {transition.Name}"));
    

This is a basic setup to get you started. Customize the indicators, conditions, states, and transitions as per your trading strategy.


Example of Console Application

This example is only for demonstration purposes and should not be used in a production environment. It demonstrates how to create a simple trading signal using the Taapi Signals Library.

class Program {

    // Taapi API key
    static string taapi_api_key = "YOUR_TAAPI_API_KEY";
    // Subscription type for taapi
    static SubscriptionType subscriptionType = SubscriptionType.Pro;
    

    // Main method
    static async Task Main(string[] args) {


        #region 1. Initialize Logger's

        ILoggerFactory loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
        ILogger<TaapiClient> taapiLogger = loggerFactory.CreateLogger<TaapiClient>();
        ILogger<EventManager> signalEventManager = loggerFactory.CreateLogger<EventManager>();

        #endregion


        #region 2. Initialize Signal Manager, Taapi Client, Event Manager

        // Initialize taaapi client
        var taapiClient = new TaapiClient(taapiLogger, taapi_api_key, subscriptionType);

        // Initialize event manager
        var eventManager = new EventManager(signalEventManager);

        // Initialize signal manager
        var signalManager = new SignalManager(loggerFactory, taapiClient, eventManager);

        #endregion


        #region 4. Create a new signal

        SignalModel signalModel = new SignalModel {
            Name = "SignalTest_Strategy",
            Description = "Test if signal manger works correctly",
        };

        #endregion


        #region 5. Define Indicators needed for the signal

        // RSI indicator for transition condition
        IndicatorModel IndicatorRsiCondition = new IndicatorModel {
            Name = "RsiCondition",
            IndicatorRequest = new IndicatorRequest {
                Exchange = "binance",
                Symbol = "BTC/USDT",
                Interval = "5m",
                Indicator = "rsi",
                AdditionalParameters = new Dictionary<string, string> {
                    { "period", "15" },
                }
            },
        };
        // RSI indicator for transition condition threshold
        IndicatorModel IndicatorRsiThreshold = new IndicatorModel {
            Name = "RsiThreshold",
            IndicatorRequest = new IndicatorRequest {
                Exchange = "binance",
                Symbol = "BTC/USDT",
                Interval = "1h",
                Indicator = "rsi",
                AdditionalParameters = new Dictionary<string, string> {
                    { "period", "15" },
                }
            },
        };
        // Supertrend indicator for AND condition with RSI
        IndicatorModel IndicatorSupertrend = new IndicatorModel {
            Name = "Supertrend",
            IndicatorRequest = new IndicatorRequest {
                Exchange = "binance",
                Symbol = "BTC/USDT",
                Interval = "1h",
                Indicator = "supertrend",
                Backtrack = 1,
                AdditionalParameters = new Dictionary<string, string> {
                    { "period", "10" },
                    { "multiplier", "3" }
                }
            },
        };

        // ATR indicator for stop loss line
        IndicatorModel IndicatorAtr = new IndicatorModel {
            Name = "Atr",
            IndicatorRequest = new IndicatorRequest {
                Exchange = "binance",
                Symbol = "BTC/USDT",
                Interval = "1h",
                Indicator = "atr",
                AdditionalParameters = new Dictionary<string, string> {
                    { "period", "14" },
                }
            },
        };

        // Add indicators to the signal
        signalModel.Indicators.Add(IndicatorRsiCondition);
        signalModel.Indicators.Add(IndicatorRsiThreshold);
        signalModel.Indicators.Add(IndicatorSupertrend);
        signalModel.Indicators.Add(IndicatorAtr);

        #endregion


        #region 6. Define signal states

        // Start state with initial flag ( FSM will start from this state )
        var startState = new SignalState { Name = "Start", IsInitial = true };
        // Sate wher we are waiting for the trading signal
        var idleState = new SignalState { Name = "Idle" };
        // State where we are trading, inthis we set the stop loss
        var tradeState = new SignalState { 
            Name = "Trade",
            StopLoss = new StopLossModel {
                Indicator = IndicatorAtr,
                IndicatorValueName = "value",
                IndicatorMultiplier = 1.5m
            }
        };

        signalModel.States.Add(startState);
        signalModel.States.Add(idleState);
        signalModel.States.Add(tradeState);

        #endregion


        #region 7. Define indicators conditions and composite conditions

        // Final composite condition with RSI and Supertrend with OR logic -> (5 MIN RSI > 1 HOUR RSI ) || SUPERTREND == LONG )
        // If five minute RSI is greater than one hour RSI, and Supertrend is long, then transition to Trade state
        // This condition is used for the final transition from Idle to Trade state

        // RSI condition with dynamic threshold from RSI indicator -> ( CONDITION: 5 MIN RSI > 1 HOUR RSI )
        var rsiConditionDynamicThreshold = new IndicatorCondition {
            IndicatorModel = IndicatorRsiCondition,
            SubValueKey = "value",
            ConditionOperator = ConditionOperator.GreaterThan,
            //Threshold = 0m,
            IsDynamicThreshold = true, // Dynamic threshold based on the indicator value
            ThresholdIndicator = IndicatorRsiThreshold, // Indicator for dynamic threshold,
            ThresholdSubValueKey = "value" // Sub value key for dynamic threshold
        };

        // Supertrend condition with static threshold -> ( CONDITION: SUPERTREND == LONG )
        var supertrendCondition = new IndicatorCondition {
            IndicatorModel = IndicatorSupertrend,
            SubValueKey = "valueAdvice",
            ConditionOperator = ConditionOperator.Equal,
            Threshold = "long" // Static threshold for Supertrend,
        };

        // Wrappers for indicator conditions
        var rsiConditionDynamicThresholdWrapper = new IndicatorConditionWrapper(rsiConditionDynamicThreshold, loggerFactory.CreateLogger<IndicatorConditionWrapper>());
        var supertrendConditionWrapper = new IndicatorConditionWrapper(supertrendCondition, loggerFactory.CreateLogger<IndicatorConditionWrapper>());

        // Composite condition with RSI and Supertrend with AND logic -> ( CONDITION: (5 MIN RSI > 1 HOUR RSI ) && SUPERTREND == LONG )
        var compositeCondition = new CompositeCondition(loggerFactory.CreateLogger<CompositeCondition>()) {
            LogicOperator = LogicOperator.And,
            Conditions = new List<BaseCondition>
            {
                rsiConditionDynamicThresholdWrapper,    // RSI -> ( CONDITION: 5 MIN RSI > 1 HOUR RSI )
                supertrendConditionWrapper // SUPERTREND ->  ( CONDITION: SUPERTREND == LONG )
            }
        };


        // RSI condition with static threshold -> ( CONDITION: 5 MIN RSI > 75 )
        var rsiCondition = new IndicatorCondition {
            IndicatorModel = IndicatorRsiCondition,
            SubValueKey = "value",
            ConditionOperator = ConditionOperator.GreaterThan,
            Threshold = 75,
        };
        // Wrapper for RSI condition
        var rsiConditionConditionWrapper = new IndicatorConditionWrapper(rsiCondition, loggerFactory.CreateLogger<IndicatorConditionWrapper>());

        #endregion


        #region 8. Define event driven conditions

        // Event driven condition for price crossed above specific value
        var priceCrossedCondition = new EventDrivenCondition {
            EventName = "PriceCrossed", // Ime dogodka
            Predicate = parameters => (decimal)parameters["Price"] > 50 // Predicate to check if the condition is met, (if )
        };

        // Event driven condition for button pressed
        var buttonPressedCondition = new EventDrivenCondition {
            EventName = "ButtonPressed", // Name of the event
            Predicate = _ => true // Predicate to check if the condition is met, for button press it is always true
        };

        #endregion


        #region 9. Add transitions to the signal with conditions

        // Transition from Start to Idle state
        var transitionStartToIdle = new StateTransition {
            Name = "StartToIdle",
            Description = "Transition from Start to Idle state",
            FromState = startState,
            ToState = idleState,
            Conditions = new List<BaseCondition> { compositeCondition }, // Conditions based on the indicators
            EventDrivenConditions = new List<EventDrivenCondition> {  buttonPressedCondition } // Event driven conditions
        };
        signalModel.Transitions.Add(transitionStartToIdle);

        // Transition from Idle to Trade state
        var transitionIdleToTrade = new StateTransition {
            Name = "IdleToTrade",
            Description = "Transition from Idle to Trade state",
            FromState = idleState,
            ToState = tradeState,
            Conditions = new List<BaseCondition> { compositeCondition },
            EventDrivenConditions = new List<EventDrivenCondition> { priceCrossedCondition }
        };
        signalModel.Transitions.Add(transitionIdleToTrade);

        // Transition from Trade to Idle state
        var transitionTradeToIdle = new StateTransition {
            Name = "TradeToIdle",
            Description = "Transition from Trade to Idle state",
            FromState = tradeState,
            ToState = idleState,
            Conditions = new List<BaseCondition> { rsiConditionConditionWrapper }
        };
        signalModel.Transitions.Add(transitionTradeToIdle);

        #endregion


        #region 10. Validate signal model

        try {

            // Validate signal model if needed for some reason
            signalManager.ValidateSignalModel(signalModel);
        }
        catch (ArgumentException ex) {
            Console.WriteLine($"Argument Exception: {ex.Message}");
            return;
        }
        catch (InvalidOperationException ex) {
            Console.WriteLine($"Invalid Operation Exception: {ex.Message}");
            return;
        }
        catch (Exception ex) {
            Console.WriteLine($"Error: {ex.Message}");
            return;
        }

        #endregion


        #region 11. Save signal model to the signal manager

        try {

            // Save signal model to the signal manager,
            // method will first validate the model and throw exception if model is not valid
            signalModel.Id = await signalManager.CreateSignal(signalModel);
        }
        catch (ArgumentException ex) {
            Console.WriteLine($"Argument Exception: {ex.Message}");
            return;
        }
        catch (InvalidOperationException ex) {
            Console.WriteLine($"Invalid Operation Exception: {ex.Message}");
            return;
        }
        catch (Exception ex) {
            Console.WriteLine($"Error: {ex.Message}");
            return;
        }

        #endregion


        #region 12. Register to signal events

        // Register to signal events
        signalManager.SubscribeToEvents(signalModel.Id,
            beforeTransition: BeforeTransitionEvent,
            afterTransition: AfterTransitionEvent,
            onEnterState: OnEnterStateEvent,
            onExitState: OnExitStateEvent,
            onIndicatorValueFetched: OnIndicatorValueFetchedEvent
            );

        tradeState.StopLoss.OnStopLossCalculatedEvent += OnStopLossCalculated;


        #endregion


        #region 13. Start fetching signal

        // Start fetching signal
        //signalManager.StartAutoFetching(signalModel.Id, new TimeSpan(0,1,0));

        #endregion


        #region 13. Test event driven conditions

        // Not met conditions
        eventManager.TriggerEvent("PriceCrossed", new Dictionary<string, object> { { "Price", 40 } });

        // Wait for 5 seconds
        await Task.Delay(5000);

        // Met conditions
        eventManager.TriggerEvent("ButtonPressed", new Dictionary<string, object>());

        // Wait for 5 seconds
        await Task.Delay(5000);

        // Met conditions
        eventManager.TriggerEvent("PriceCrossed", new Dictionary<string, object> { { "Price", 60 } });

        #endregion

        // Wait for user input to stop the program
        Console.WriteLine("Press any key to stop the program");
        Console.ReadKey();

    }//end Main()


    // Before Transition Event
    private static void BeforeTransitionEvent(SignalService service, StateTransition transition) {

        Console.WriteLine($"Before transitioning from {transition.FromState.Name} to {transition.ToState.Name}");
    }//end BeforeTransitionEvent()



    // After Transition Event
    private static void AfterTransitionEvent(SignalService service, StateTransition transition) {

        Console.WriteLine($"After transitioning from {transition.FromState.Name} to {transition.ToState.Name}");
    }//end AfterTransitionEvent()


    // On Enter State Event
    private static void OnEnterStateEvent(SignalService service, SignalState state) {

        Console.WriteLine($"Entered state: {state.Name}");
    }//end OnEnterStateEvent()


    // On Exit State Event
    private static void OnExitStateEvent(SignalService service, SignalState state) {

        Console.WriteLine($"Exited state: {state.Name}");
    }//end OnExitStateEvent()


    // On Indicator Value Fetched Event
    private static void OnIndicatorValueFetchedEvent(string indicatorKey, object indicatorValue) {

        Console.WriteLine($"Indicator value fetched: {indicatorKey} = {indicatorValue}");
    }//end OnIndicatorValueFetchedEvent()


    // On Stop Loss Calculated Event
    public static void OnStopLossCalculated( string stateName, decimal stopLossValue) {

        Console.WriteLine($"Stop loss calculated for state {stateName}: {stopLossValue}");
    }//end OnStopLossCalculated()

}// class

Contributing

Contributions are welcome! If you have any questions, suggestions, or you want to contribute to this project, feel free to contact me at info@grumson.eu


License

This project is licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE for more information.


Support

Use this link to register on Taapi.io and you will support me with a small commission. Thank you!

If you like this project and you want to support it, you can donate to the following addresses:

Network BSC BNB smart chain (BEP20) : 0xd8c509ed7d8f96847618d926e2b831d804e02ece

  • BNB : 0xd8c509ed7d8f96847618d926e2b831d804e02ece
  • USDT : 0xd8c509ed7d8f96847618d926e2b831d804e02ece

Network Solana (SPL) : 4D1W3Vv2tbfAzuEgBSiNGqdtGT5wUjbodoF6mXEsnvTf

  • SOL : 4D1W3Vv2tbfAzuEgBSiNGqdtGT5wUjbodoF6mXEsnvTf
  • USDC : 4D1W3Vv2tbfAzuEgBSiNGqdtGT5wUjbodoF6mXEsnvTf

Network Ethereum (ERC20) : 0xd8c509ed7d8f96847618d926e2b831d804e02ece

  • ETH : 0xd8c509ed7d8f96847618d926e2b831d804e02ece
  • USDC : 0xd8c509ed7d8f96847618d926e2b831d804e02ece

BTC : 19pxXzh1Kzzw73v6iKbowr1DJro5ozgZj6


Changelog

Version 1.0.8 (05.02.2025)
- Bug fixes:
    - Fixed bug in condition evaluation when the indicator value is not with decimal point, but with comma.
Version 1.0.7 (30.01.2025)
- Add methods to SignalManager: 
    - GetBulkRequest(SignalModel signalModel)
    - GetBulkResponsesAsync(Guid signalId)
    - GetBulkResponsesAsync(SignalModel signalModel)
Version 1.0.6 (27.01.2025)
- Add methods to SignalManager: 
    - GetBulkRequest(Guid signalId, SignalModel signalModel) to get the bulk request for specific signal model, to validate the signal indicators before creating the signal
    - GetBulkRequest(Guid signalId), to get the bulk request for created signal in the signal manager
    - GetBulkResponsesAsync(Guid signalId, BulkRequest bulkRequest), to get signals data for the bulk request, to chek if the indicators settings are working correctly

- Set deprecated methods to SignalManager:
    - CreateSignal(SignalModel signalModel), use CreateSignalAsync(SignalModel signalModel) instead
Version 1.0.5 (23.01.2025)
- when signal go to new state and this state has static stop loss it will rise event OnStopLossCalculated with the stop loss value. Just for the first time when the signal goes to the state.
Version 1.0.4 (23.01.2025)
- Add Stop Loss value to the signal state. 
    - Now you can allso set the static stop loss value for each state of the signal. Not just the dynamic thru the indicator value.
Version 1.0.3 (23.01.2025)
- Some minor bug fixes and improvements.
Version 1.0.1 (22.01.2025)
- Added event driven conditions to the signal model.
Version 1.0.0 (21.01.2025)
- Initial release of the Taapi Signals Library.
Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Grumson.Utilities.Taapi.Signals:

Package Downloads
Grumson.Utilities.Taapi.Signals.Blazor

The Taapi Signals Blazor Razor Class Library (RCL) is a reusable component library built for managing and visualizing trading signals using the Taapi Signals Library. This Razor Class Library provides a UI layer for defining, testing, and managing trading signals in a structured manner, utilizing **Finite State Machines (FSMs)**.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.8 0 2/5/2025
1.0.7 66 1/30/2025
1.0.6 61 1/27/2025
1.0.4 73 1/23/2025
1.0.3 82 1/22/2025
1.0.2 79 1/22/2025
1.0.1 72 1/22/2025
1.0.0 73 1/21/2025