Trailing Stoploss Execution Module

Internet Function Method

// Rajandran R - Creator of OpenAlgo
// Website - openalgo.in / marketcalls.in
// OpenAlgo - Amibroker Trailing Stoploss Execution Module
// Date - 13/12/2024


_SECTION_BEGIN("OpenAlgo Trailing Stoploss Execution Module");

// Initial setup and parameters
RequestTimedRefresh(1, False);
EnableTextOutput(False);

// OpenAlgo Configuration Parameters
apikey = ParamStr("OpenAlgo API Key", "******");
strategy = ParamStr("Strategy", "TSL_Strategy");
symbol = ParamStr("Symbol", "YESBANK");
exchange = ParamList("Exchange", "NSE|NFO|BSE|MCX|CDS");
product = ParamList("Product", "MIS|NRML|CNC");
quantity = Param("Quantity", 1, 1, 1000, 1);
host = ParamStr("Host", "http://127.0.0.1:5000");
ver = ParamStr("API Version", "v1");
VoiceAlert = ParamList("Voice Alert", "Disable|Enable", 1);
EnableAlgo = ParamList("Algo Mode", "Disable|Enable", 0);
TestMode = ParamList("Test Mode", "Disable|Enable", 0);

// TSL Specific Parameters
StopLevel = 1 - Param("Trailing Stop %", 3, 0.1, 10, 0.1)/100;
Order_TickSize = Param("Order Tick Size", 1, 0.01, 1, 0.01);
Entrydelay = Param("Entry Delay", 0, 0, 1, 1);
Exitdelay = Param("Exit Delay", 0, 0, 1, 1);

reset = ParamTrigger("Memory Reset","Reset Now");

// Function to round price to nearest tick size
function RoundToTickSize(price, tickSize) {
    return Floor(price/tickSize + 0.5) * tickSize;
}

// Initialize static variables
bridgeurl = host + "/api/" + ver;
static_name_ = Name() + GetChartID() + interval(2) + strategy;
static_name_algo = static_name_ + interval(2) + strategy + "algostatus";
static_name_tsl = static_name_ + "_tsl";
static_name_orderid = static_name_ + "_orderid";

if(reset)
{

StaticVarRemove(static_name_+"_tsl");
StaticVarRemove(static_name_+"_orderid");

}

// HTTP Post Request Function
function HttpPostRequest(url, postData) {
    headers = "Content-Type: application/json\r\n" +
              "Accept-Encoding: gzip, deflate\r\n";
    InternetSetHeaders(headers);
    ih = InternetPostRequest(url, postData);
    response = "";
    if(ih) {
        while((line = InternetReadString(ih)) != "") 
            response += line;
        InternetClose(ih);
    }
    return response;
}

// JSON Value Extraction Function
function ExtractJsonValue(jsonStr, key, isNested) {
    result = "";
    jsonData = jsonStr;

    if(isNested) {
        dataStart = StrFind(jsonStr, "\"data\":{");
        if(dataStart > 0) dataStart = dataStart - 1;
        
        if(dataStart >= 0) {
            valueStart = dataStart + 7;
            valueEnd = valueStart;
            braceCount = 1;
            strLenJson = StrLen(jsonStr);

            while(valueEnd < strLenJson) {
                currChar = StrMid(jsonStr, valueEnd, 1);
                if(currChar == "{") braceCount++;
                if(currChar == "}") braceCount--;
                if(braceCount == 0) break;
                valueEnd++;
            }
            
            jsonData = StrMid(jsonStr, valueStart, valueEnd - valueStart);
        }
    }
    
    keyPos = StrFind(jsonData, "\"" + key + "\":");
    if(keyPos > 0) keyPos = keyPos - 1;
    
    if(keyPos > -1) {
        valueStart = keyPos + StrLen(key) + 3;
        while(StrMid(jsonData, valueStart, 1) == " ") valueStart++;
        
        firstValChar = StrMid(jsonData, valueStart, 1);
        isQuoted = (firstValChar == "\"");
        
        strLenData = StrLen(jsonData);
        valueEnd = valueStart;
        
        if(isQuoted) {
            valueStart++;
            valueEnd = valueStart;
            while(valueEnd < strLenData) {
                currChar = StrMid(jsonData, valueEnd, 1);
                if(currChar == "\"") break; 
                valueEnd++;
            }
            result = StrMid(jsonData, valueStart, valueEnd - valueStart);
        } else {
            while(valueEnd < strLenData) {
                currChar = StrMid(jsonData, valueEnd, 1);
                if(currChar == "," OR currChar == "}") break;
                valueEnd++;
            }
            result = StrMid(jsonData, valueStart, valueEnd - valueStart);
        }
    }
    
    return result;
}

// Order Management Functions
function PlaceStopLossMarketOrder(action, triggerPrice) {
    postData = "{\"apikey\": \"" + apikey + "\", " +
               "\"strategy\": \"" + strategy + "\", " +
               "\"symbol\": \"" + symbol + "\", " +
               "\"action\": \"" + action + "\", " +
               "\"exchange\": \"" + exchange + "\", " +
               "\"pricetype\": \"SL-M\", " +
               "\"price\": \"0\", " +  // Price is 0 for SL-M orders
               "\"trigger_price\": \"" + triggerPrice + "\", " +
               "\"product\": \"" + product + "\", " +
               "\"quantity\": \"" + quantity + "\"}";
    _TRACE("SL-M Order Request: " + postData);
    response = HttpPostRequest(bridgeurl + "/placeorder", postData);
    _TRACE("SL-M Order Response: " + response);
    return response;
}

function CheckOrderStatus(orderid) {
    postData = "{\"apikey\": \"" + apikey + "\", " +
               "\"strategy\": \"" + strategy + "\", " +
               "\"orderid\": \"" + orderid + "\"}";
    response = HttpPostRequest(bridgeurl + "/orderstatus", postData);
    _TRACE("Order Status Check for OrderID " + orderid + " Response: " + response);
    return response;
}

function ModifyStopLossMarketOrder(orderid, triggerPrice) {
    postData = "{\"apikey\": \"" + apikey + "\", " +
               "\"strategy\": \"" + strategy + "\", " +
               "\"symbol\": \"" + symbol + "\", " +
               "\"action\": \"SELL\", " +  // Added action field
               "\"exchange\": \"" + exchange + "\", " +
               "\"orderid\": \"" + orderid + "\", " +
               "\"product\": \"" + product + "\", " +
               "\"pricetype\": \"SL-M\", " +
               "\"price\": \"0\", " +  // Price is 0 for SL-M orders
               "\"trigger_price\": \"" + triggerPrice + "\", " +
               "\"quantity\": \"" + quantity + "\", " +
               "\"disclosed_quantity\": \"0\"}";  // Added disclosed_quantity field
    _TRACE("Modify SL-M Order Request for OrderID " + orderid + ": " + postData);
    response = HttpPostRequest(bridgeurl + "/modifyorder", postData);
    _TRACE("Modify SL-M Order Response: " + response);
    return response;
}

function PlaceMarketEntry(action) {
    postData = "{\"apikey\": \"" + apikey + "\", " +
               "\"strategy\": \"" + strategy + "\", " +
               "\"symbol\": \"" + symbol + "\", " +
               "\"action\": \"" + action + "\", " +
               "\"exchange\": \"" + exchange + "\", " +
               "\"pricetype\": \"MARKET\", " +
               "\"product\": \"" + product + "\", " +
               "\"quantity\": \"" + quantity + "\"}";
    
    _TRACE("Market Entry Order Request: " + postData);
    response = HttpPostRequest(bridgeurl + "/placeorder", postData);
    _TRACE("Market Entry Order Response: " + response);
    return response;
}

// Trading signals
Buy = Cross(MACD(), Signal());
Sell = 0;
trailARRAY = Null;
trailstop = 0;

// Calculate Trailing Stop Level
for(i = 1; i < BarCount; i++) {
    if(trailstop == 0 AND Buy[i]) { 
        trailstop = High[i] * StopLevel;
        //_TRACE("New TSL Level calculated: " + trailstop);
    }
    else Buy[i] = 0;
    
    if(trailstop > 0 AND Low[i] < trailstop) {
        Sell[i] = 1;
        SellPrice[i] = trailstop;
        //_TRACE("TSL Hit - Sell Signal Generated at: " + trailstop);
        trailstop = 0;
    }
    
    if(trailstop > 0) {
        newTSL = Max(High[i] * StopLevel, trailstop);
        if(newTSL != trailstop) {
            //_TRACE("TSL Level Updated from " + trailstop + " to " + newTSL);
            trailstop = newTSL;
        }
        trailARRAY[i] = trailstop;
    }
}

// Execution Logic
AlgoBuy = LastValue(Ref(Buy, -Entrydelay));
AlgoSell = LastValue(Ref(Sell, -Exitdelay));
currentTSL = RoundToTickSize(LastValue(trailARRAY), Order_TickSize);
//_TRACE("Raw TSL: " + LastValue(trailARRAY) + ", Rounded to tick size: " + currentTSL);

if(EnableAlgo == "Enable") {
    // Print current stored OrderID
    printf("\nAlgo Mode Enabled");
    storedOrderId = StaticVarGetText(static_name_orderid);
    printf("\nCurrent Stored OrderID: " + storedOrderId);
    printf("\nCurrent TSL: " + currentTSL);
    
    // Entry Logic
    if(AlgoBuy AND Nz(StaticVarGet(static_name_ + "entryAlgo")) == 0) {
        _TRACE("Buy Signal Detected - Executing Market Entry");
        entryResponse = PlaceMarketEntry("BUY");
        
        if(entryResponse != "") {
            _TRACE("Entry Order Executed Successfully");
            if(currentTSL > 0) {
                _TRACE("Placing Initial TSL SL-M Order at trigger: " + currentTSL);
                tslResponse = PlaceStopLossMarketOrder("SELL", currentTSL);
                
                if(tslResponse != "") {
                    orderid = ExtractJsonValue(tslResponse, "orderid", False);
                    if(orderid != "") {
                        StaticVarSetText(static_name_orderid, orderid);
                        StaticVarSet(static_name_tsl, currentTSL);
                        _TRACE("New TSL OrderID Stored: " + orderid);
                        if(VoiceAlert == "Enable") Say("Entry and TSL Orders Placed");
                    }
                }
            }
            StaticVarSet(static_name_ + "entryAlgo", 1);
        }
    }
    
    // TSL Modification Logic
    if(currentTSL > 0 AND currentTSL != StaticVarGet(static_name_tsl)) {
        orderid = StaticVarGetText(static_name_orderid);
        _TRACE("Checking TSL Order: " + orderid);
        
        if(orderid != "") {
            statusResponse = CheckOrderStatus(orderid);
            if(statusResponse != "") {
                orderStatus = ExtractJsonValue(statusResponse, "order_status", True);
                _TRACE("Current TSL Order Status: " + orderStatus);
                
                if(orderStatus == "open") {
                    _TRACE("Modifying SL-M Order " + orderid + " trigger from " + StaticVarGet(static_name_tsl) + " to " + currentTSL);
                    modifyResponse = ModifyStopLossMarketOrder(orderid, currentTSL);
                    if(modifyResponse != "") {
                        StaticVarSet(static_name_tsl, currentTSL);
                        _TRACE("TSL Order Modified Successfully");
                    }
                }
            }
        }
    }
    
    // Exit Logic
    if(AlgoSell AND Nz(StaticVarGet(static_name_ + "exitAlgo")) == 0) {
        orderid = StaticVarGetText(static_name_orderid);
        _TRACE("TSL Hit - Checking Order: " + orderid);
        
        if(orderid != "") {
            statusResponse = CheckOrderStatus(orderid);
            if(statusResponse != "") {
                orderStatus = ExtractJsonValue(statusResponse, "order_status", True);
                _TRACE("TSL Hit - Order Status: " + orderStatus);
                
                if(orderStatus == "complete") {
                    _TRACE("TSL Order " + orderid + " Executed Successfully");
                    if(VoiceAlert == "Enable") Say("Trailing Stop Loss Hit");
                    StaticVarSet(static_name_ + "exitAlgo", 1);
                    // Clear the stored OrderID
                    StaticVarSetText(static_name_orderid, "");
                }
            }
        }
    }
}

Plot(trailARRAY, "Trailing Stop Level", colorRed);

_SECTION_END();

_SECTION_BEGIN("Trading Signals");


//Plot the trading signals

/* Plot Buy and Sell Signal Arrows */
PlotShapes(IIf(Buy, shapeSquare, shapeNone),colorGreen, 0, L, Offset=-40);
PlotShapes(IIf(Buy, shapeSquare, shapeNone),colorLime, 0,L, Offset=-50);                      
PlotShapes(IIf(Buy, shapeUpArrow, shapeNone),colorWhite, 0,L, Offset=-45); 
PlotShapes(IIf(Sell, shapeSquare, shapeNone),colorRed, 0, H, Offset=40);
PlotShapes(IIf(Sell, shapeSquare, shapeNone),colorOrange, 0,H, Offset=50);                      
PlotShapes(IIf(Sell, shapeDownArrow, shapeNone),colorWhite, 0,H, Offset=-45);



_SECTION_END();

_SECTION_BEGIN("Candlestick Charts with Date & Time Axis");

//Enable the Date & Time Axis
SetChartOptions(0, chartShowArrows | chartShowDates);

//Plotting Candlestick charts
Plot(Close,"Candle",colorDefault,styleCandle);


_SECTION_END();

Last updated