// File Name: HMACross_2_1ChartTrader.cpp

#include "sierrachart.h"      // Main Sierra Chart ACSIL header
#include "scstructures.h"     // Include the Fuck me! corrected scstructures.h for structures like SCString, s_SCTradeOrder
#include <cmath>              // For fabsf and fabs

// Define the DLL name for Sierra Chart identification
SCDLLName("HMACross_2_1ChartTrader")

SCSFExport scsf_HMACross_2_1ChartTrader(SCStudyInterfaceRef sc)
{
    // --- Inputs ---
    SCInputRef Input_HMA11 = sc.Input[0];
    SCInputRef Input_HMA21 = sc.Input[1];
    SCInputRef Input_HMA37 = sc.Input[2];

    SCInputRef Input_Angle11 = sc.Input[3];
    SCInputRef Input_Angle21 = sc.Input[4];
    SCInputRef Input_Angle37 = sc.Input[5];

    SCInputRef Input_RSI = sc.Input[6];
    SCInputRef Input_DIPlus = sc.Input[7];
    SCInputRef Input_DIMinus = sc.Input[8];
    SCInputRef Input_ADX = sc.Input[9];

    SCInputRef Input_RSIThreshold = sc.Input[10];
    SCInputRef Input_HMADistanceThreshold = sc.Input[11];
    SCInputRef Input_ADXThreshold = sc.Input[12];

    SCInputRef Input_EnableTrading = sc.Input[13];
    SCInputRef Input_EnableRSI = sc.Input[14];
    SCInputRef Input_EnableDI = sc.Input[15];
    SCInputRef Input_EnableADX = sc.Input[16];
    SCInputRef Input_EnableHMADistanceChecks = sc.Input[17];
    SCInputRef Input_EnableAngleChecks = sc.Input[18];

    // Add new input settings for HMA distance thresholds
    SCInputRef Input_HMA11_HMA21_DistanceThreshold = sc.Input[19];
    SCInputRef Input_HMA21_HMA37_DistanceThreshold = sc.Input[20];
    // --- Subgraphs ---
    SCSubgraphRef Subgraph_BuyEntry = sc.Subgraph[0];
    SCSubgraphRef Subgraph_SellExit = sc.Subgraph[1];

    // Persistent variable to track script active state
    int& isScriptActive = sc.GetPersistentInt(1);
    // Static variables to maintain state
    static bool signalExecuted = false;

    // Set defaults on the first run
    if (sc.SetDefaults)
    {
        sc.GraphName = "HMACross_2_1ChartTrader";
        sc.StudyDescription = "A strategy that signals entries based on the crossover of HMA lines.";
        sc.AutoLoop = 1; // Enable automatic looping
        sc.GraphRegion = 0; // Main price graph
        sc.CalculationPrecedence = LOW_PREC_LEVEL;

        // Initialize the script active state
        isScriptActive = 1; // Start with the script active
        // log the initialization parameters 
        sc.AddMessageToLog("HMACross_2_1ChartTrader initialized", 0);

        // Initialize Input Names and Settings
        Input_HMA11.Name = "HMA11 (Study and Subgraph)";
        Input_HMA11.SetStudySubgraphValues(5, 0); // Study ID 5, Subgraph 0

        Input_HMA21.Name = "HMA21 (Study and Subgraph)";
        Input_HMA21.SetStudySubgraphValues(6, 0); // Study ID 6, Subgraph 0

        Input_HMA37.Name = "HMA37 (Study and Subgraph)";
        Input_HMA37.SetStudySubgraphValues(7, 0); // Study ID 7, Subgraph 0

        Input_Angle11.Name = "Angle11 (Study and Subgraph)";
        Input_Angle11.SetStudySubgraphValues(8, 0); // Ensure these values are correct

        Input_Angle21.Name = "Angle21 (Study and Subgraph)";
        Input_Angle21.SetStudySubgraphValues(9, 0); // Ensure these values are correct

        Input_Angle37.Name = "Angle37 (Study and Subgraph)";
        Input_Angle37.SetStudySubgraphValues(11, 0); // Ensure these values are correct

        Input_RSI.Name = "RSI (Study and Subgraph)";
        Input_RSI.SetStudySubgraphValues(15, 0); // Study ID 15, Subgraph 0

        Input_DIPlus.Name = "DI+ (Study and Subgraph)";
        Input_DIPlus.SetStudySubgraphValues(2, 0); // Study ID 2, Subgraph 0

        Input_DIMinus.Name = "DI- (Study and Subgraph)";
        Input_DIMinus.SetStudySubgraphValues(2, 1); // Study ID 2, Subgraph 1

        Input_ADX.Name = "ADX (Study and Subgraph)";
        Input_ADX.SetStudySubgraphValues(3, 0); // Study ID 3, Subgraph 0

        Input_RSIThreshold.Name = "RSI Threshold for Entry";
        Input_RSIThreshold.SetFloat(25.0f);

        Input_HMADistanceThreshold.Name = "HMA Distance Threshold for Entry";
        Input_HMADistanceThreshold.SetFloat(5.0f);

        Input_ADXThreshold.Name = "ADX Threshold for Trend Strength";
        Input_ADXThreshold.SetFloat(15.0f);

        // Initialize Enable Inputs
        Input_EnableTrading.Name = "Enable Trading (Yes = 1, No = 0)";
        Input_EnableTrading.SetYesNo(1);

        Input_EnableRSI.Name = "Enable RSI (Yes = 1, No = 0)";
        Input_EnableRSI.SetYesNo(0);

        Input_EnableDI.Name = "Enable DMI (Yes = 1, No = 0)";
        Input_EnableDI.SetYesNo(0);

        Input_EnableADX.Name = "Enable ADX (Yes = 1, No = 0)";
        Input_EnableADX.SetYesNo(0);

        Input_EnableHMADistanceChecks.Name = "Enable HMA Distance Checks (Yes = 1, No = 0)";
        Input_EnableHMADistanceChecks.SetYesNo(0);

        // Input_EnableAngleChecks.Name = "Enable Angle Checks (Yes = 1, No = 0)";
        // Input_EnableAngleChecks.SetYesNo(1);

        Input_HMA11_HMA21_DistanceThreshold.Name = "HMA11 to HMA21 Distance Threshold for Entry";
        Input_HMA11_HMA21_DistanceThreshold.SetFloat(2.0f);

        Input_HMA21_HMA37_DistanceThreshold.Name = "HMA21 to HMA37 Distance Threshold for Entry";
        Input_HMA21_HMA37_DistanceThreshold.SetFloat(2.0f);
        // Initialize Subgraphs
        Subgraph_BuyEntry.Name = "Buy Entry";
        Subgraph_BuyEntry.DrawStyle = DRAWSTYLE_POINT_ON_HIGH;
        Subgraph_BuyEntry.PrimaryColor = RGB(0, 255, 0); // Green
        Subgraph_BuyEntry.LineWidth = 3;

        Subgraph_SellExit.Name = "Sell Exit";
        Subgraph_SellExit.DrawStyle = DRAWSTYLE_POINT_ON_LOW;
        Subgraph_SellExit.PrimaryColor = RGB(255, 0, 0); // Red
        Subgraph_SellExit.LineWidth = 3;

        // Trade Management Settings
        sc.AllowMultipleEntriesInSameDirection = false;
        sc.MaximumPositionAllowed = 1; // Only one position at a time
        sc.SupportReversals = true;

        sc.SendOrdersToTradeService = false; // Use simulation system
        sc.AllowOppositeEntryWithOpposingPositionOrOrders = false;
        sc.SupportAttachedOrdersForTrading = true; // Enable attached orders

        sc.CancelAllOrdersOnEntriesAndReversals = true;
        sc.AllowEntryWithWorkingOrders = false;
        sc.CancelAllWorkingOrdersOnExit = true;
        sc.AllowOnlyOneTradePerBar = true;

        sc.MaintainTradeStatisticsAndTradesData = true;
        return;
    }

    // Create a button on the chart
    s_UseTool Button;
    Button.Clear();
    Button.ChartNumber = sc.ChartNumber;
    Button.DrawingType = DRAWING_TEXT;
    Button.BeginDateTime = 0; // Position at the start of the chart
    Button.BeginValue = static_cast<float>(sc.YPixelCoordinateToGraphValue(20)); // Position at the top of the chart
    Button.Text = isScriptActive ? "Stop Script" : "Start Script";
    Button.Color = RGB(255, 255, 255); // White text
    Button.FontSize = 12;
    Button.AddMethod = UTAM_ADD_OR_ADJUST;
    Button.LineNumber = 1; // Unique line number for the button

    sc.UseTool(Button);

    // Check for button click
    if (sc.MenuEventID == 1)
    {
        // Toggle the script active state
        isScriptActive = !isScriptActive;
        sc.AddMessageToLog(isScriptActive ? "Script started." : "Script stopped.", 1);
    }

    // Only execute the script if it is active
    if (!isScriptActive)
    {
        return;
    }
    // Reset `signalExecuted` at new bar

    if (sc.GetBarHasClosedStatus() == BHCS_BAR_HAS_CLOSED)
    {
        signalExecuted = false;
        sc.AddMessageToLog("New bar detected, resetting signalExecuted flag.", 0);
    }

        // Check if trading is enabled
    if (Input_EnableTrading.GetYesNo() == 0)
    {
        sc.AddMessageToLog("Trading is disabled.", 0);
        return;
    }

    // Retrieve HMA study arrays
    SCFloatArray HMA11;
    sc.GetStudyArrayUsingID(Input_HMA11.GetStudyID(), Input_HMA11.GetSubgraphIndex(), HMA11);

    SCFloatArray HMA21;
    sc.GetStudyArrayUsingID(Input_HMA21.GetStudyID(), Input_HMA21.GetSubgraphIndex(), HMA21);

    SCFloatArray HMA37;
    sc.GetStudyArrayUsingID(Input_HMA37.GetStudyID(), Input_HMA37.GetSubgraphIndex(), HMA37);

    // Retrieve angle study arrays
    SCFloatArray Angle11;
    sc.GetStudyArrayUsingID(Input_Angle11.GetStudyID(), Input_Angle11.GetSubgraphIndex(), Angle11);

    SCFloatArray Angle21;
    sc.GetStudyArrayUsingID(Input_Angle21.GetStudyID(), Input_Angle21.GetSubgraphIndex(), Angle21);

    SCFloatArray Angle37;
    sc.GetStudyArrayUsingID(Input_Angle37.GetStudyID(), Input_Angle37.GetSubgraphIndex(), Angle37);

    // Retrieve RSI study arrays
    SCFloatArray RSI;
    sc.GetStudyArrayUsingID(Input_RSI.GetStudyID(), Input_RSI.GetSubgraphIndex(), RSI);

    // Retrieve DMI study arrays
    SCFloatArray DIPlus;
    sc.GetStudyArrayUsingID(Input_DIPlus.GetStudyID(), Input_DIPlus.GetSubgraphIndex(), DIPlus);

    SCFloatArray DIMinus;
    sc.GetStudyArrayUsingID(Input_DIMinus.GetStudyID(), Input_DIMinus.GetSubgraphIndex(), DIMinus);

    //Retrieve ADX study arrays
    SCFloatArray ADX;
    sc.GetStudyArrayUsingID(Input_ADX.GetStudyID(), Input_ADX.GetSubgraphIndex(), ADX);



    // Verify that all required subgraphs are available
    if (HMA11.GetArraySize() == 0 || HMA21.GetArraySize() == 0 || HMA37.GetArraySize() == 0 ||
        Angle11.GetArraySize() == 0 || Angle21.GetArraySize() == 0 || Angle37.GetArraySize() == 0 ||
        RSI.GetArraySize() == 0 || DIPlus.GetArraySize() == 0 || DIMinus.GetArraySize() == 0 ||
        ADX.GetArraySize() == 0)
    {
        sc.AddMessageToLog("One or more required subgraphs are not available. Aborting.", 1);
        return;
    }

    // Calculate HMA differences
    float HMA11_HMA37_Diff = fabsf(HMA11[sc.Index] - HMA37[sc.Index]);
    float HMA11_HMA21_Diff = fabsf(HMA11[sc.Index] - HMA21[sc.Index]);
    float HMA21_HMA37_Diff = fabsf(HMA21[sc.Index] - HMA37[sc.Index]);

    // Evaluate conditions
    bool RSIConditionMet = (!Input_EnableRSI.GetYesNo() || RSI[sc.Index] > Input_RSIThreshold.GetFloat());
    bool DMIConditionMet = (!Input_EnableDI.GetYesNo() || DIPlus[sc.Index] > DIMinus[sc.Index]);
    bool ADXConditionMet = (!Input_EnableADX.GetYesNo() || ADX[sc.Index] > Input_ADXThreshold.GetFloat());

    bool HMADistanceOK = true;
    if (Input_EnableHMADistanceChecks.GetYesNo())
    {
        HMADistanceOK = (HMA11_HMA37_Diff > Input_HMADistanceThreshold.GetFloat() &&
                         HMA11_HMA21_Diff > Input_HMA11_HMA21_DistanceThreshold.GetFloat() &&
                         HMA21_HMA37_Diff > Input_HMA21_HMA37_DistanceThreshold.GetFloat());
    }
    // Log the current settings for HMA distance checks
    SCString hmaDistanceCheckSettings;
    hmaDistanceCheckSettings.Format("HMA Distance Checks Enabled: %d, HMA11 to HMA21 Distance Threshold: %.2f, HMA21 to HMA37 Distance Threshold: %.2f",
        Input_EnableHMADistanceChecks.GetYesNo(), 
        Input_HMA11_HMA21_DistanceThreshold.GetFloat(), 
        Input_HMA21_HMA37_DistanceThreshold.GetFloat());
    sc.AddMessageToLog(hmaDistanceCheckSettings, 1);

    
    // Calculate the distances between HMA values
    float hma11ToHma21Distance = fabsf(HMA11[sc.Index] - HMA21[sc.Index]); // Calculate the distance between HMA11 and HMA21
    float hma21ToHma37Distance = fabsf(HMA21[sc.Index] - HMA37[sc.Index]); // Calculate the distance between HMA21 and HMA37

    // Log the calculated distances
    SCString hmaDistanceValues;
    hmaDistanceValues.Format("Calculated HMA Distances - HMA11 to HMA21: %.2f, HMA21 to HMA37: %.2f",
        hma11ToHma21Distance, hma21ToHma37Distance);
    sc.AddMessageToLog(hmaDistanceValues, 1);


    // Check if the distance checks are enabled and determine if conditions are met
    bool HMA_D_T = false; // Initialize the HMA distance condition variable
    if (Input_EnableHMADistanceChecks.GetYesNo() == 1)
    {
        if (hma11ToHma21Distance > Input_HMA11_HMA21_DistanceThreshold.GetFloat() &&
            hma21ToHma37Distance > Input_HMA21_HMA37_DistanceThreshold.GetFloat())
        {
            sc.AddMessageToLog("HMA distance conditions met for entry.", 1);
            HMA_D_T = true; // Set the variable to true when conditions are met
        }
        else
        {
            sc.AddMessageToLog("HMA distance conditions not met for entry.", 1);
        }
    }
    else
    {
        sc.AddMessageToLog("HMA distance checks are disabled.", 1);
        HMA_D_T = true; // Assume conditions are met if checks are disabled
    }

    // Get current trade position
    s_SCPositionData PositionData;
    sc.GetTradePosition(PositionData);

    // Log the current trade position data
    SCString positionDataLog;
    positionDataLog.Format("Position Quantity: %d, Position Average Price: %.2f, Position Profit/Loss: %.2f",
    PositionData.PositionQuantity, PositionData.AveragePrice, PositionData.OpenProfitLoss);
    sc.AddMessageToLog(positionDataLog, 1);

    // Store position data in persistent variables
    sc.SetPersistentInt(0, static_cast<int>(PositionData.PositionQuantity)); // Explicitly cast to int
    sc.SetPersistentDouble(0, PositionData.AveragePrice);
    sc.SetPersistentDouble(1, PositionData.OpenProfitLoss);


    // Use persistent variables to construct exit logic
    int storedPositionQuantity = sc.GetPersistentInt(0);
    double storedAveragePrice = sc.GetPersistentDouble(0);
    double storedOpenProfitLoss = sc.GetPersistentDouble(1);

    // Entry logic
    // Calculate exit logic based on the stored position data
    // crossover condition for HMAs
    // Determine crossover value
    int HMA11_CA_HMA21 = sc.CrossOver(HMA11, HMA21);

        // Long Entry Logic
        if (!signalExecuted && PositionData.PositionQuantity == 0 && // Ensure no current position
                HMA11_CA_HMA21 == CROSS_FROM_BOTTOM && // Use the correct crossover condition for entry
                HMA_D_T) // Check if HMA distance conditions are met
        {
                // Log the entry conditions
                sc.AddMessageToLog("Entry conditions met. Preparing to submit entry order.", 1);
                // Create a market order to enter a new long position
                s_SCNewOrder NewEntryOrder;

                // Set the order quantity directly from the trade window
                NewEntryOrder.OrderQuantity = sc.TradeWindowOrderQuantity;
                //log order quantity
                SCString orderQuantityLog;
                orderQuantityLog.Format("Order quantity set to: %d", sc.TradeWindowOrderQuantity);
                sc.AddMessageToLog(orderQuantityLog, 1);

                // Define the order type and time in force
                NewEntryOrder.OrderType = sc.GetTradeWindowOrderType();
                NewEntryOrder.TimeInForce = SCT_TIF_GOOD_TILL_CANCELED;

                // Log the order details
                SCString entryOrderDetails;
                entryOrderDetails.Format("Entry order details: OrderType=%d, OrderQuantity=%d, TimeInForce=%d",
                NewEntryOrder.OrderType, NewEntryOrder.OrderQuantity, NewEntryOrder.TimeInForce);
                sc.AddMessageToLog(entryOrderDetails, 1);

                // Submit Buy Entry Order
                int EntryOrderID = static_cast<int>(sc.BuyEntry(NewEntryOrder));

                // Check if order submission was successful
                if (EntryOrderID > 0)
                {
                    signalExecuted = true;
                    SCString message;
                    message.Format("Entry order submitted successfully. Order ID: %d", EntryOrderID);
                    sc.AddMessageToLog(message, 1);
                }
                else
                {
                    SCString failureMessage;
                    failureMessage.Format("Entry order submission failed. BuyEntry returned: %d", EntryOrderID);
                    sc.AddMessageToLog(failureMessage, 1);
                }
        }
            
// Calculate the crossover condition for angles
    // Define constants for crossover conditions
    // const int CROSS_FROM_BOTTOM = 1;
    // const int CROSS_FROM_TOP = -1;
    // crossover condition for angles
    
    
    // Crossover condition for angles
    int Angle11_CB_Angle21 = sc.CrossOver(Angle11, Angle21);
    if (PositionData.PositionQuantity == 1 && Angle11_CB_Angle21 == CROSS_FROM_TOP) // Use the correct crossover condition for exit
    {
        // Log the intention to exit the trade
        sc.AddMessageToLog("Preparing to exit the trade based on crossover condition.", 1);
        // Exit the trade
        s_SCNewOrder ExitOrder;
        ExitOrder.OrderQuantity = static_cast<int>(PositionData.PositionQuantity); // Explicitly cast to int

        // Log the exit order details
        SCString exitOrderDetails;
        exitOrderDetails.Format("Exit order details: OrderQuantity=%d", ExitOrder.OrderQuantity);
        sc.AddMessageToLog(exitOrderDetails, 1);
        int Result = static_cast<int>(sc.BuyExit(ExitOrder));

        // Check if order submission was successful
        if (Result > 0)
        {
            SCString message;
            message.Format("Exit order submitted successfully. Result: %d", Result);
            sc.AddMessageToLog(message, 1);
        }
        else
        {
            SCString failureMessage;
            failureMessage.Format("Exit order submission failed. BuyExit returned: %d", Result);
            sc.AddMessageToLog(failureMessage, 1);
        }
    }

}        


