SMMDH v3.4-DeadCat
betaDescription
Hey guys, so based on Cosmos DeadCat structure (Kiling it in this market!) I have (with the help of multiple GPTs - might be some halucinations in there still)
Merged it with SMMDH and some commands I personally use to make hybrid trades.
-- IDEA --
CC_DeadCat - works as a pivot detector with a focus on deadcat market structure -
Script waits for signal from DeadCat - Pivots- and then deploys a grid for X amount of time (this insures it works counter trend at all times) + maximum X amount of fills (so we dont load multiple cycles)
Once the fills are loaded, by using fast price, it then uses trending indicators to TP/SL or manualli set static percentage levels (there is no hard SL -- Everything works via de-risking so MM logic remains intact)
Let me know what you guys think in the comments, specially of how would you improve it :ok_hand:
HaasScript
-- Modified version of Phsai's amazing Simple Market Maker - ENHANCED with Killzones + Force controls + Dynamic Spread + Indicator Gating
-- ONLY FOR BINANCE FUTURES USDT/COIN HEDGE MODE ENABLED
EnableHighSpeedUpdates(true)
HideOrderSettings()
HideTradeAmountSettings()
-- ==================== BOT SETTINGS ====================
InputGroupHeader('Bot Settings')
local okLong = Input('01. Allow Long', true, 'Allow bot to open Long')
local okShort = Input('02. Allow Short', true, 'Allow bot to open Short')
local wtfStop = Input('03. Stop at no position', false, 'Deactivate bot when there is no open position')
local FStop = Input('04. Force Close Position', false, 'Closes open positions')
local forceCloseLong = Input('04A. Force Close Long', false, 'Force close long position only')
local forceCloseShort = Input('04B. Force Close Short', false, 'Force close short position only')
local forceOpenLong = Input('04C. Force Open Long', false, 'Force open long position')
local forceOpenShort = Input('04D. Force Open Short', false, 'Force open short position')
local fprices = InputInterval('05. Fast Price Interval', 1, 'Set required interval')
local showInfo = Input('06. Details in Log', true, 'Show detail information in logs about the bot condition')
local allowWeekends = Input('07. Allow Weekends', false, 'Allow new orders on weekends, still within killzones')
local okKillzone = Input('08. Enable ICT Killzones', true, 'When OFF bot places orders continuously (no time restriction)')
local okAsianKZ = Input('09. Enable Asian Killzone', true, 'Allow trading in Asian Killzone (01:00-03:00 UTC)')
local okLondonKZ = Input('10. Enable London Killzone', true, 'Allow trading in London Killzone (07:00-10:00 UTC)')
local okNYKZ = Input('11. Enable New York Killzone', true, 'Allow trading in New York Killzone (12:00-15:00 UTC)')
local okLondonCloseKZ = Input('12. Enable London Close Killzone', true, 'Allow trading in London Close Killzone (15:00-17:00 UTC)')
local cancelAtEndKZ = Input('13. Cancel at End of KZ', true, 'Cancel non-closing orders when exiting killzone')
InputGroupHeader('Backtest Settings')
local wtfBal = Input('01. Deactivate on Over Budget', false, 'Deactivate when Working Balance > Budget Balance')
local wtfRatio = Input('02. Deactivate on specific Bal Ratio', false, 'Deactivate when Bal Ratio hit trigger below')
local wtfRatioV = Input('02A. Bal Ratio Trigger', 0.5)
local wtfAmount = Input('03. Deactivate on Over Size', false, 'Deactivate when one of position size > Max Open')
local wtfWallet = Input('04. Deactivate on Wallet = 0', false, 'Why bother continuing the backtest?')
local testWallet = Input('05. Use Custom Wallet', false, 'ONLY FOR BACKTEST. DO NOT USE WHEN ON RUNNING BOT')
local testWalletAmount= Input('05A. Custom Wallet Balance', 0, 'ONLY FOR BACKTEST. DO NOT USE WHEN ON RUNNING BOT')
InputGroupHeader('LONG and SHORT Ratio')
local enableRatio = Input('01. Enable ratios', false)
local longRatio = Input('01A. Long ratio', 4, 'Long ratio, compared to short, default is 1, must be greater than 0')
local shortRatio = Input('01B. Short ratio', 1, 'Short ratio, compared to long, default is 1, must be greater than 0')
InputGroupHeader('Budget & Safety')
local maxSizeM = Input('01. Max. Open ', 100, 'Maximum open contracts at any given time also as minimum for Dynamic Max Open. After exceeding this value, the bot will dump a portion of position at a loss.')
local autoMax = Input('01A. Dynamic Max Open', false, 'Dynamically change max open contracts based on available balanca')
local leverage = GetLeverage()
local contVal = ContractValue()
local budgetTypes = {'Fix', 'Percentage'}
local budgetType = InputOptions('01C.Budget Calculation', 'Fix', budgetTypes, 'Fix = Static budget balance. Profit not compounding. Percentage = Dynamic following wallet balance. Profit compounding')
local budgetIsolation = Input('01D. Budget Isolation', false, 'If activated reduction is when working balance >= budget balance. Else if position size > max size')
local maxBudget = Input('01E. Balance Budget', 0, 'How much from wallet balance allocated for this bot. If % then 0.5 is 50% of wallet balance. If Fix then the fiat/coin amount.')
local maxOpen = Input('01F. Position Budget', 0.1, 'How much from the Balance Budget allocated for opening positions. 0.1 is 10% of Balance Budget')
local reduceSize = Input('02. Size Reduction %', 21, 'How big of a portion the bot will dump once reduction condition triggered')
local reduceOrderType = InputOrderType('03. Reduction Order Type', MarketOrderType, 'The order type for size reduction dump')
local noReduce = Input('04. Disable Size Reduction', true, 'Are you sure?')
InputGroupHeader('Grid Settings')
local slotCount = Input('01. Slot Count', 1, 'How many orders are constantly kept open on both long and short side')
local slotSizeM = Input('02. Slot Size', 0.001, 'Minimum trade amount per slot if Dynamic Slot Size activated or fix value if bot dynamic')
local slotRefillCount = Input('01. Slot Refill Count', 3, 'How many times can the slot orders be refilled')
local slotMultiplier = Input('02A. Slot Size Multiplier', 2, 'Trade amount multipler per slot')
local autoSlot = Input('03A. Dynamic Slot Size', false, 'DSSize - Dynamically change slot size based on budget')
local slotBudget = Input('03B. Max. Open Divider', 377, 'DSSize feature - Divide max open position with this value to get new Slot Size. Example Max Open is 1000 and devider is 200 then slot size is 5')
local slotSpreadL = Input('04A. Slot Spread Long %', 0.7, 'Percentage for longs based spread value between each slot')
local slotSpreadS = Input('04B. Slot Spread Short %', 0.7, 'Percentage for shorts based spread value between each slot')
local slotSpreadM = Input('04C. Slot Spread Multiplier', 1, 'Order Spread Multipler per slot')
local incLVLOneShort = Input('04C. LVL 1 inc Short size at %', 10, 'Level 1 increase for shorts in Percentage')
local slotCancel = Input('05. Cancel Distance %', 0.636, 'How much price can move to the opposite direction before orders are cancelled and replaced')
local minSpreadInput = Input('06. Minimum Spread %', 0.636, 'Minimum spread percentage between the first long and short entries. This setting only works when bot has no position.')
local dynamicSpreadInterval = InputInterval("07. Dynamic Spread Interval", 15)
local dynamicSpreadLookback = Input("07A. Dynamic Spread Lookback", 3)
local okDynamicSpread = Input('07B. Enable Dynamic Spread', true, 'Make Long/Short spread dynamic based on per-side exposure, and set cancel/min spread to 1/3 of it')
InputGroupHeader('Profit Settings')
local takeProfitL = Input('01. LONG Take-Profit %', 0.436, 'Fixed take-profit value, based on price change')
local takeProfitS = Input('02. SHORT Take-Profit %', 0.246, 'Fixed take-profit value, based on price change')
local takeminProfitL = Input('03. LONG MIN Take-Profit %', 0.236, 'MIN take-profit value, based on price change used by STP')
local takeminProfitS = Input('04. SHORT MIN Take-Profit %', 0.236, 'MIN take-profit value, based on price change used by STP')
local tpOrderType = InputOrderType('05. TP Order Type', MakerOrCancelOrderType, 'The order type for take-profit')
local preplacedTP = Input('06. Pre-Place TP (disabled if Smart Take Profit if is Active)', false, 'Place Exit Position as soon as has open position uses Max %')
InputGroupHeader('Indicator')
local value1_ind = InputInterval("MarketStructureDeadCat", 240, "Custom value for MarketStructureDeadCat paramete.")
-- MODIFIED: New inputs for signal window and max fills per trigger
local okSignalWindow = Input('02. Enable Signal Time Window', true, 'Force a time window after indicator signal for placing new orders')
local signalWindowMinutes = Input('03. Signal Window Duration (minutes)', 5, 'Time window after signal to allow new orders (if enabled)')
local maxFillsPerTrigger = Input('04. Max Orders Filled Per Trigger', 3, 'Maximum slot orders that can fill per indicator signal trigger')
-- price and data
local getMarket = PriceMarket()
local isBinance = StringContains(getMarket, 'BINANCE')
local SRCounter = Load('SRCounter', 0)
local c = ClosePrices()
local h = HighPrices()
local l = LowPrices()
local o = OpenPrices()
local cp = CurrentPrice()
local vol = GetVolume()
local currentPrice = CurrentPrice().close
local lbid = GetOrderbookBid()
local sask = GetOrderbookAsk()
local h1 = HighPrices(1)
local l1 = LowPrices(1)
local o1 = OpenPrices(1)
local cp1 = CurrentPrice(1)
--Trend
local cci = CCI(h, l, c, 14)
local adosc = ADOSC(h,l,c,vol,5,34)
local sar = SAR(h,l,0.04,0.4)
local ema = EMA(c,7)
local ematrendup = IsRisingSince(ema,24) == 1
local ematrenddn = IsFallingSince(ema,24) == 1
local trenddir = Load("trenddir", trenddir)
--State Toggle
function updateMyVariable()
if ematrenddn == false and IsRising(ema, 5) then
trenddir = 1
elseif ematrendup == false and IsFalling(ema, 5) then
trenddir = 2
else trenddir = 0
end
Save("trenddir", trenddir)
return trenddir
end
updateMyVariable()
-- MODIFIED: Removed trendl/trends definitions and plots, as trend is no longer used for gating
-- positions
local hedge_longPosId = Load('hedge_longPosId', NewGuid())
local hedge_shortPosId = Load('hedge_shortPosId', NewGuid())
local dir_l = GetPositionDirection(hedge_longPosId)
local aep_l = GetPositionEnterPrice(hedge_longPosId)
local pamt_l = GetPositionAmount(hedge_longPosId)
local delta_l = pamt_l > 0 and (cp.close - aep_l) / aep_l * 100 or 0
local proi_l = delta_l * leverage
local dir_s = GetPositionDirection(hedge_shortPosId)
local aep_s = GetPositionEnterPrice(hedge_shortPosId)
local pamt_s = GetPositionAmount(hedge_shortPosId)
local delta_s = pamt_s > 0 and (aep_s - cp.close) / aep_s * 100 or 0
local proi_s = delta_s * leverage
if showInfo then
Log('LONG position ROI: '..Round(proi_l, 2)..'%')
Log('SHORT position ROI: '..Round(proi_s, 2)..'%')
end
-- manage position ids
if pamt_l == 0 and IsPositionClosed(hedge_longPosId) then
if IsAnyOrderOpen(hedge_longPosId) then
CancelAllOrders(hedge_longPosId)
else
hedge_longPosId = NewGuid()
dir_l = GetPositionDirection(hedge_longPosId)
aep_l = GetPositionEnterPrice(hedge_longPosId)
pamt_l = GetPositionAmount(hedge_longPosId)
proi_l = GetPositionROI(hedge_longPosId)
end
end
if pamt_s == 0 and IsPositionClosed(hedge_shortPosId) then
if IsAnyOrderOpen(hedge_shortPosId) then
CancelAllOrders(hedge_shortPosId)
else
hedge_shortPosId = NewGuid()
dir_s = GetPositionDirection(hedge_shortPosId)
aep_s = GetPositionEnterPrice(hedge_shortPosId)
pamt_s = GetPositionAmount(hedge_shortPosId)
proi_s = GetPositionROI(hedge_shortPosId)
end
end
-- get pos id
local getPositionId = function(isLong)
return isLong and hedge_longPosId or hedge_shortPosId
end
--Dynamic Spread
local candleSpread = HighPrices(dynamicSpreadInterval) - LowPrices(dynamicSpreadInterval)
local candleSpreadWithLookback = Range(candleSpread, 0, dynamicSpreadLookback)
local averageSpread = Round(Average(candleSpreadWithLookback), 8)
local averageSpreadPercentage = Round(averageSpread / CurrentPrice().close * 100, 4)
if showInfo then
Log("Dynamic Average Spread: "..averageSpread.." "..QuoteCurrency())
Log("Dynamic Average Spread: "..averageSpreadPercentage.."%")
end
local minSpread = minSpreadInput / 2.0
-- wallet check
local profitLabel = ProfitLabel()
if profitLabel == nil then profitLabel = QuoteCurrency() end
local availBal = WalletAmount(getMarket, profitLabel)
local getProfitL = GetCurrentProfit(PositionLong)
local getProfitS = GetCurrentProfit(PositionShort)
local getProfit = getProfitL + getProfitS
local usedLong = UsedMargin(getMarket, aep_l, pamt_l, leverage)
local usedShort = UsedMargin(getMarket, aep_s, pamt_s, leverage)
--Log('usedLong '..usedLong..' usedShort '..usedShort)
local botProfit = GetBotProfit()
-- balance warning
local walletBal = testWallet and (testWalletAmount + botProfit) or availBal
local workBal = usedLong + usedShort - getProfit
if budgetType == 'Fix' then
budgetBal = IfElse(walletBal > maxBudget, maxBudget, walletBal)
else
budgetBal = maxBudget * walletBal
end
--Log('walletBal '..walletBal)
local budRatio = budgetBal > 0 and workBal / budgetBal or 0
local walRatio = budgetBal > 0 and workBal / walletBal or 0
local balRatio = budgetIsolation and budRatio or walRatio
if balRatio > 0.5 and balRatio < 0.8 and budgetIsolation then Log('Working balance is > 50% of Budget!!!', Yellow) end
if balRatio > 0.8 and budgetIsolation then Log('Working balance is > 80% of Budget!!!', Yellow) end
if walRatio > 0.8 then LogWarning('WALLET IN DANGER. Working balance is > 80% of WALLET Balance!!!') end
if showInfo then
Log('Balance Monitor -> Wallet: '..Round(walletBal, 5)..' '..profitLabel..' | Budget: '..Round(budgetBal, 5)..' '..profitLabel..' | Working Balance: '..Round(workBal, 5)..' '..profitLabel..' | Ratio: '..Round(balRatio, 3))
end
if budgetType == 'Percentage' then
if maxBudget > 1 then
DeactivateBot('Percentage Budget calculation. Balance budget can not > 1', true)
end
else
if walletBal < budgetBal then
Log('Wallet Balance is lower than Budget Balance', Yellow)
end
end
local BRCounter = Load('BRCounter', 0)
if balRatio > BRCounter then Save('BRCounter', balRatio) end
-- dynamics
--max position
if profitLabel == 'USD' or profitLabel == 'USDT' or profitLabel == 'BUSD' or profitLabel == 'USDC' or profitLabel == 'TUSD' then
maxMax = budgetBal * maxOpen / cp.close
else
maxMax = budgetBal * maxOpen * cp.close / contVal
end
local maxCheck = autoMax and (maxMax * leverage)
local maxValue = autoMax and (maxCheck > maxSizeM) and maxCheck or maxSizeM
local maxSize = autoMax and maxValue or maxSizeM
-- check max open
if autoMax then
if maxCheck > maxSizeM then
if showInfo then
Log('Dynamic Max Open: '..Round(maxCheck, 5))
end
else
if showInfo then
Log('Dynamic Max Open: '..Round(maxCheck, 5)..' but using default value: '..Round(maxSizeM, 5))
end
end
end
-- auto slot size
local slotCheck = autoSlot and (maxSize / slotBudget)
local slotValue = autoSlot and (slotCheck > slotSizeM) and slotCheck or slotSizeM
local slotSize = autoSlot and slotValue or slotSizeM
local getSlotRatio = function (size)
local baseRatio
if longRatio >= shortRatio then
baseRatio = longRatio
else
baseRatio = shortRatio
end
return baseRatio
end
local calcRatioSlotSize = function (size, ratio, long)
if long == true then
if ratio == longRatio then
local round = Round(size, 2)
return ArrayGet(round, 1)
elseif ratio == shortRatio then
local round = Round(((longRatio / shortRatio) * size), 2)
return ArrayGet(round, 1)
end
end
if long == false then
if ratio == shortRatio then
local round = Round(size, 2)
return ArrayGet(round, 1)
elseif ratio == longRatio then
local round = Round(((shortRatio / longRatio) * size), 2)
return ArrayGet(round, 1)
end
end
end
if autoSlot then
if slotCheck > slotSizeM then
slotSizeL = slotSize
slotSizeS = slotSize
if enableRatio == true and longRatio > 0 and shortRatio > 0 then
local base = getSlotRatio(slotSize)
slotSizeL = calcRatioSlotSize(slotSize, base, true)
slotSizeS = calcRatioSlotSize(slotSize, base, false)
if pamt_s > (maxSize / incLVLOneShort) then
LogWarning("It's bigger than 10 %")
slotSizeS = slotSizeS * (longRatio / shortRatio)
end
end
if showInfo then
Log('Dynamic Slot Size for long: '..Round(slotSizeL, 5))
Log('Dynamic Slot Size for short: '..Round(slotSizeS, 5))
end
else
slotSizeL = slotSize
slotSizeS = slotSize
if enableRatio == true and longRatio > 0 and shortRatio > 0 then
local base = getSlotRatio(slotSize)
slotSizeL = calcRatioSlotSize(slotSize, base, true)
slotSizeS = calcRatioSlotSize(slotSize, base, false)
if pamt_s > (maxSize / incLVLOneShort) then
LogWarning("It's bigger than 10 %")
slotSizeS = slotSizeS * (longRatio / shortRatio)
end
end
if showInfo then
Log('DSSize: '..Round(slotCheck, 5)..' But using default value: '..Round(slotSizeM, 5))
end
end
else
slotSizeL = slotSizeM
slotSizeS = slotSizeM
if enableRatio == true and longRatio > 0 and shortRatio > 0 then
local base = getSlotRatio(slotSize)
slotSizeL = calcRatioSlotSize(slotSize, base, true)
slotSizeS = calcRatioSlotSize(slotSize, base, false)
if pamt_s > (maxSize / incLVLOneShort) then
LogWarning("It's bigger than 10 %")
slotSizeS = slotSizeS * (longRatio / shortRatio)
end
end
if showInfo then
Log('Slot Size Value for long: '..Round(slotSizeL, 5))
Log('Slot Size Value Value for short: '..Round(slotSizeS, 5))
end
end
--Smart Params
local fcp = ClosePrices({interval = fprices})
local cint = CurrentInterval()
local isLongPosOpen = not IsPositionClosed(hedge_longPosId) and LongAmount() > 0
local isShortPosOpen = not IsPositionClosed(hedge_shortPosId) and ShortAmount() > 0
--Smart TTP EXIT
--Smart TTP Params
InputGroupHeader('Smart Take Profit')
local okSmartTP = Input('01. Smart Take Profit ', false, 'Allow Smart Take Profit')
--local hardTakeProfitPercentage = Input(' 03. Hard Take Profit', 0.35, 'Hard Take Profit Percentage linked to Price Movement.')
--local stttp = Input('Trigger Trailing Take Profit(TTP)', 0.15, 'Start TTP after Price Movement Trigger % is breached')
local ltpt = Load("LTPT")
local lhtpt = Load("LHTPT")
local stpt = Load("STPT")
local shtpt = Load("SHTPT")
--TTP
local laep = GetPositionEnterPrice(hedge_longPosId)
local saep = GetPositionEnterPrice(hedge_shortPosId)
local LstartPoint = AddPercentage(laep, takeminProfitL)
local SstartPoint = SubPercentage(saep, takeminProfitS)
--Log("LstartPoint: "..LstartPoint.."-")
--Log("SstartPoint: "..SstartPoint.."-")
function LSmartTTPExit()
local lhasTriggered = false
if isLongPosOpen and lhtpt == 0 then
lhtpt = AddPercentage(laep, takeProfitL)
elseif isLongPosOpen and currentPrice >= LstartPoint and o[1] > o[2] and o[2] > o[3] and currentPrice < c[2] then
ltpt = o[3]
end
lhasTriggered = (isLongPosOpen and currentPrice >= lhtpt) or (isLongPosOpen and currentPrice >= LstartPoint and ltpt > LstartPoint)
if lhasTriggered then
PlotSignalBar(-4, Olive)
end
Save("LTPT", ltpt)
Save("LHTPT", lhtpt)
return lhasTriggered
end
Log("Long TTP: "..tostring(ltpt))
Log("Long TP: "..tostring(lhtpt))
function SSmartTTPExit()
local shasTriggered = false
if isShortPosOpen and shtpt == 0 then
shtpt = SubPercentage(saep, takeProfitS)
elseif isShortPosOpen and currentPrice <= SstartPoint and o[1] < o[2] and o[2] < o[3] and currentPrice > c[2] then
stpt = o[3]
end
shasTriggered = (isShortPosOpen and currentPrice >= shtpt) or (isShortPosOpen and currentPrice <= SstartPoint and stpt < SstartPoint)
if shasTriggered then
PlotSignalBar(-4, Maroon )
end
Save("STPT", stpt)
Save("SHTPT", shtpt)
return shasTriggered
end
Log("Short TTP: ".. tostring(stpt))
Log("Short TP: "..tostring(shtpt))
--Log("o[2]: ".. tostring(o[2]))
--Long Smart TP Exit
if isLongPosOpen and okSmartTP and LSmartTTPExit() and OrderOncePerBar(cint,hedge_longPosId) then
if fcp <= ltpt and ltpt > 0 and fcp > LstartPoint then
ltpoid = PlaceExitPositionOrder(hedge_longPosId, cp, MarketOrderType, 'Long TTP Exit', (cint * 2))
elseif fcp <= lhtpt and lhtpt > 0 then
ltpoid = PlaceExitPositionOrder(hedge_longPosId, lhtpt, MarketOrderType, 'Long TP Exit', (cint * 2))
if IsOrderFilled(ltpoid) then
PlotSignalBar(-4, '#a1d99b')
ltpoid = ''
end
if not IsOrderOpen(ltpoid) then
ltpoid = ''
end
Save("LTPOID", ltpoid)
end
end
--Short Smart TP Exit
if isShortPosOpen and okSmartTP and SSmartTTPExit() and OrderOncePerBar(cint,hedge_shortPosId) then
if fcp >= stpt and stpt > 0 and fcp < SstartPoint then
stpoid = PlaceExitPositionOrder(hedge_shortPosId, cp, MarketOrderType, 'Short TTP Exit', (cint * 2))
elseif fcp <= shtpt and shtpt > 0 then
stpoid = PlaceExitPositionOrder(hedge_shortPosId, shtpt, MarketOrderType, 'Short TP Exit', (cint * 2))
if IsOrderFilled(stpoid) then
PlotSignalBar(-4, '#ef6548')
stpoid = ''
end
if not IsOrderOpen(stpoid) then
stpoid = ''
end
Save("STPOID", stpoid)
end
end
--End Smart TTP
-- Smart SL Exit
-- Smart Stop Loss
InputGroupHeader('Smart Stop Loss')
local okSmartSL = Input('01. Smart Stop Loss ', true, 'Allow Smart Stop Loss')
local hardStopLossPercentage = Input(' 03. Hard StopLoss', 0.35, 'Hard StopLoss Percentage linked to Price Movement.')
local stslt = Input('Trigger Adjust HardStop Loss to prevent Loss ', 0.15, 'Start Trigger for Ave Entry Price Adj % linked to Price Movement')
local lhsl = Load("LHSLT")
local ltsl = Load("LTSL")
local shsl = Load("SHSLT")
local stsl = Load("STSL")
-- SL
local laep = GetPositionEnterPrice(hedge_longPosId)
local saep = GetPositionEnterPrice(hedge_shortPosId)
local LstartPoint = AddPercentage(laep, stslt)
local SstartPoint = SubPercentage(saep, stslt)
function LSmartSLExit()
local lhasTriggered = false
if isLongPosOpen and lhsl == 0 then
lhsl = SubPercentage(laep, hardStopLossPercentage)
elseif isLongPosOpen and currentPrice >= LstartPoint and not c[2] < c[1] then
lhsl = AddPercentage(laep, 0.2)
end
lhasTriggered = isLongPosOpen and currentPrice <= lhsl
if lhasTriggered then
PlotSignalBar(-3, Olive)
end
Save("LHSLT", lhsl)
return lhasTriggered
end
function SSmartSLExit()
local shasTriggered = false
if isShortPosOpen and shsl == 0 then
shsl = AddPercentage(saep, hardStopLossPercentage)
elseif isShortPosOpen and currentPrice <= SstartPoint and not c[2] > c[1] then
shsl = SubPercentage(saep, 0.2)
end
shasTriggered = isShortPosOpen and currentPrice >= shsl
if shasTriggered then
PlotSignalBar(-3, Maroon)
end
Save("SHSLT", shsl)
return shasTriggered
end
--Long Smart SL Exit
if isLongPosOpen and okSmartSL and LSmartSLExit() and OrderOncePerBar(cint,hedge_longPosId) then --and IsFalling(apo,1) and IsFalling(trendemaf,1) then
if fcp <= lhsl then
CancelAllOrders()
lhsloid = PlaceExitPositionOrder(hedge_longPosId, lhsl, MarketOrderType, 'Long SL Exit', (cint * 2))
if IsOrderFilled(lhsloid) then
PlotSignalBar(-3, '#a1d99b')
lhsloid = ''
end
if not IsOrderOpen(lhsloid) then
lhsloid = ''
end
Save("LHSLOID", lhsloid)
end
end
--Short Smart SL Exit
if isShortPosOpen and okSmartSL and SSmartSLExit() and OrderOncePerBar(cint,hedge_shortPosId) then --and IsRising(apo,1) and IsRising(trendemaf,1) then
if fcp >= shsl then
CancelAllOrders()
shsloid = PlaceExitPositionOrder(hedge_shortPosId, shsl, MarketOrderType, 'Short SL Exit', (cint * 2))
if IsOrderFilled(shsloid) then
PlotSignalBar(-3, '#ef6548')
shsloid = ''
end
if not IsOrderOpen(shsloid) then
shsloid = ''
end
Save("SHSLOID", shsloid)
end
end
--End Smart SL Exit
--Reset Smart values
if not isLongPosOpen then
lhsl = 0
ltsl = 0
ltpt = 0
lhtpt = 0
Save("LTSL", ltsl)
Save("LHSLT", lhsl)
Save("LTPT", ltpt)
Save("LHTPT", lhtpt)
end
if not isShortPosOpen then
shsl = 0
stsl = 0
stpt = 0
shtpt = 0
Save("STSL", stsl)
Save("SHSLT", shsl)
Save("STPT", stpt)
Save("SHTPT", shtpt)
end
-- SMM CORE LOGIC HEDGE MODE
-- slot function
-- MODIFIED: Removed 'trend' parameter from slot function (no longer gates on trend)
local slot = function(isLong, index, amount, spread, cancelDist, canPlace)
local prefix = isLong and 'L' or 'S'
local name = prefix .. index
local cmd = isLong and PlaceGoLongOrder or PlaceGoShortOrder
local priceBase = isLong and cp.bid or cp.ask
local spr = Min(averageSpreadPercentage, minSpread) + spread * index
local posId = getPositionId(isLong)
local aep = isLong and aep_l or aep_s
-- if we have average entry price
if aep > 0 then
priceBase = isLong
and Min(aep, priceBase)
or Max(aep, priceBase)
end
-- get price
local price = isLong
and SubPerc(priceBase, spr)
or AddPerc(priceBase, spr)
-- Binance notional value mod
if isBinance then
notionalSize = 5.1 / price
if amount < notionalSize then
amount = notionalSize
end
end
local oid = Load(name..'oid', '') -- order id
if oid != '' then
local order = OrderContainer(oid)
if order.isOpen then
local delta = isLong
and Delta(AddPerc(order.price, spr), priceBase)
or Delta(priceBase, SubPerc(order.price, spr))
if delta >= cancelDist then
CancelOrder(oid)
LogWarning('Delta cancelled '..name)
elseif not canPlace then
CancelOrder(oid)
LogWarning('Not allowed right now '..name)
end
else
oid = ''
end
else
if canPlace then
oid = cmd(price, amount, {type = MakerOrCancelOrderType, note = name, timeout = 3600, positionId = posId})
end
end
Save(name..'oid', oid)
end
-- update take-profit
local updateTakeProfit = function(isLong, entryPrice, targetRoi, cancelDist)
local prefix = isLong and 'Long' or 'Short'
local name = prefix .. ' TP'
local oid = Load(prefix .. 'tp_oid', '')
local timer = Load(prefix .. 'tp_timer', 0)
local posId = getPositionId(isLong)
local tp_delta = isLong and Delta(entryPrice, cp.bid) or Delta(cp.ask, entryPrice)
if oid != '' then
local order = OrderContainer(oid)
if order.isOpen then
local delta = isLong
and Delta(order.price, cp.close)
or Delta(cp.close, order.price)
if delta >= cancelDist then
CancelOrder(oid)
LogWarning('Delta cancelled '..name)
end
else
if order.isCancelled then
timer = 0
end
oid = ''
end
else
if preplacedTP then
if isLong and pamt_l > 0 and not okSmartTP then
local exitL = AddPerc(aep_l, takeProfitL)
oid = PlaceExitPositionOrder({price= exitL, type = tpOrderType, note = 'Pre-Placed '..name, timeout = 200, positionId = hedge_longPosId})
end
if not isLong and pamt_s > 0 and not okSmartTP then
local exitS = SubPerc(aep_s, takeProfitS)
oid = PlaceExitPositionOrder({price= exitS, type = tpOrderType, note = 'Pre-Placed '..name, timeout = 200, positionId = hedge_shortPosId})
end
elseif not preplacedTP and tp_delta >= targetRoi and Time() >= timer and not okSmartTP then
oid = PlaceExitPositionOrder({type = tpOrderType, note = name, timeout = 200, positionId = posId})
timer = Time() + 60 -- 1min
end
end
Save(prefix .. 'tp_oid', oid)
Save(prefix .. 'tp_timer', timer)
end
-- update position size
local updatePositionManagement = function(isLong, currentSize, sizeLimit, cancelDist)
local prefix = isLong and 'Long' or 'Short'
local name = prefix .. ' Size Reduction'
local oid = Load(prefix .. 'pos_oid', '')
local posId = getPositionId(isLong)
local amount = SubPerc(currentSize, 100 - reduceSize) -- take X% of position
local price = isLong
and cp.ask
or cp.bid
local cmd = isLong
and PlaceExitLongOrder
or PlaceExitShortOrder
local timer = Load(prefix .. 'pos_timer', Time())
local okReduce = IfElse(budgetIsolation, balRatio >= 1, currentSize > sizeLimit)
if oid != '' then
local order = OrderContainer(oid)
if order.isOpen then
local delta = isLong
and Delta(order.price, cp.close)
or Delta(cp.close, order.price)
if delta >= cancelDist then
CancelOrder(oid)
LogWarning('Delta cancelled '..name)
end
elseif order.isFilled then
sizeRed = 1
Save('SRCounter', SRCounter + sizeRed)
Save('slotRefillCount', slotRefillCount + sizeRed)
oid = ''
else
oid = ''
end
else
if okReduce and not noReduce and Time() >= timer then
oid = cmd(price, amount, {type = reduceOrderType, note = name, timeout = 6000, positionId = posId})
timer = Time() + 60 -- 1min
end
end
Save(prefix .. 'pos_oid', oid)
Save(prefix .. 'pos_timer', timer)
end
-- da logica
-- take profit
updateTakeProfit(true, aep_l, takeProfitL, slotCancel)
updateTakeProfit(false, aep_s, takeProfitS, slotCancel)
-- risk management
updatePositionManagement(true, pamt_l, maxSize, slotCancel)
updatePositionManagement(false, pamt_s, maxSize, slotCancel)
-- update slots
for r = 1, slotRefillCount do
if r <= slotRefillCount then
for i = 1, slotCount do
-- MODIFIED: Removed 'trend' arg from slot call
slot(true, i, slotSizeL, slotSpreadL, slotCancel, okLong)
slotSizeL = slotSizeL * slotMultiplier
slotSpreadL = slotSpreadL * slotSpreadM
end
end
end
for r = 1, slotRefillCount do
if r <= slotRefillCount then
for i = 1, slotCount do
-- MODIFIED: Removed 'trend' arg from slot call
slot(false, i, slotSizeS, slotSpreadS, slotCancel, okShort)
slotSizeS = slotSizeS * slotMultiplier
slotSpreadS = slotSpreadS * slotSpreadM
end
end
end
-- WTF
if wtfStop then
local longNull = pamt_l == 0
local shortNull = pamt_s == 0
if longNull and shortNull then
DeactivateBot('Deactivate on No Position is active', true)
else
LogWarning('Will deactivate on No Position, waiting...maybe next second, maybe never :)')
end
end
if wtfBal then
if workBal >= budgetBal then
DeactivateBot('Over Budget', true)
end
end
if wtfAmount then
if pamt_l > maxSize or pamt_s > maxSize then
DeactivateBot('Over Size', true)
end
end
if wtfRatio then
if balRatio > wtfRatioV then
DeactivateBot('Bal Ratio is over '..wtfRatioV, true)
end
end
if wtfWallet then
if walletBal <= 0 then
DeactivateBot('Wallet is 0', true)
end
end
-- Force Exit Positions
if FStop then
local name = 'Force Exit'
oid = PlaceExitPositionOrder({type = reduceOrderType, note = name, timeout = 3600})
timer = Time() + 60 -- 1min
end
-- PLOT
-- AEP Plot
if aep_l > 0 then
local posId = getPositionId(true)
Plot(0, 'AvgEP Long', aep_l, {c=Teal, id=posId, w=2})
end
if aep_s > 0 then
local posId = getPositionId(false)
Plot(0, 'AvgEP Short', aep_s, {c=Purple, id=posId, w=2})
end
-- EXPOSURE
local lineLong = IfElse(pamt_l > 0, pamt_l, 0)
local lineShort = IfElse(pamt_s > 0, -pamt_s, 0)
Plot(1, 'Longs', lineLong, {c=Green, s=Step})
Plot(1, 'Max Longs', maxSize, {c=White, s=Step})
Plot(1, 'Shorts', lineShort, {c=Red, s=Step})
Plot(1, 'Max Shorts', -maxSize, {c=White, s=Step})
ChartSetOptions(1, 'Exposure')
--BALANCE MONITOR
Plot(2, 'Budget Balance', budgetBal, {c=White, s=Step})
Plot(2, 'WorkBal', workBal, {c=Red, s=Step})
Plot(2, 'Wallet Balance', walletBal, {c=DarkGreen, s=Step})
ChartSetOptions(2, 'Balance Monitor')
-- Misc Logs
if showInfo then
Log('Size Reduction: '..SRCounter..' times')
end
if not okLong then
LogWarning('Bot is not allowed to open LONG')
end
if not okShort then
LogWarning('Bot is not allowed to open SHORT')
end
-- custom reports
Finalize(function()
CustomReport('Final Wallet Balance', Round(walletBal, 5)..' '..profitLabel)
CustomReport('Size Reduction', SRCounter..' times')
CustomReport('Highest Balance Ratio', Round(100 * BRCounter, 2)..'%')
if testWallet then
if budgetType == 'Fix' then
profitPercent = Round(botProfit / maxBudget * 100, 2)
else
local startBal = testWalletAmount * maxBudget
profitPercent = Round(botProfit / startBal * 100, 2)
end
CustomReport('Profit %: ', profitPercent..'%')
CustomReport('Profit to Highest Bal. Ratio', Round(profitPercent / (100 * BRCounter), 2))
end
end)
Save('hedge_longPosId', hedge_longPosId)
Save('hedge_shortPosId', hedge_shortPosId)
if showInfo then
Log(' ')
end
-- ==================== KILLZONE + FORCE LOGIC ====================
local currentHour = CurrentHour()
local currentDay = CurrentDay()
local inWeekend = currentDay == 1 or currentDay == 7
local inKillzone = false
if okKillzone then
if okAsianKZ and currentHour >= 1 and currentHour < 3 then inKillzone = true end
if okLondonKZ and currentHour >= 7 and currentHour < 10 then inKillzone = true end
if okNYKZ and currentHour >= 12 and currentHour < 15 then inKillzone = true end
if okLondonCloseKZ and currentHour >= 15 and currentHour < 17 then inKillzone = true end
else
inKillzone = true
end
local canEnterNewTrades = (not okKillzone or inKillzone) and (allowWeekends or not inWeekend)
-- FORCE ACTIONS
if forceCloseLong and isLongPosOpen then PlaceExitPositionOrder(hedge_longPosId, nil, MarketOrderType, 'Force Close Long') end
if forceCloseShort and isShortPosOpen then PlaceExitPositionOrder(hedge_shortPosId, nil, MarketOrderType, 'Force Close Short') end
if forceOpenLong and not isLongPosOpen then slot(true, 1, slotSizeL, slotSpreadL, slotCancel, true) end -- MODIFIED: Removed trend
if forceOpenShort and not isShortPosOpen then slot(false, 1, slotSizeS, slotSpreadS, slotCancel, true) end -- MODIFIED: Removed trend
-- CANCEL AT END OF KILLZONE
if cancelAtEndKZ and not inKillzone and Load('lastInKZ', false) then
CancelAllOrders(hedge_longPosId)
CancelAllOrders(hedge_shortPosId)
Log('Exited Killzone → cancelled slot orders', Yellow)
end
Save('lastInKZ', inKillzone)
-- ==================== INDICATOR GATING ====================
local deadCatSignal = CC_MarketStructureDeadCat(value1_ind)
local indLongSignal = deadCatSignal == SignalLong
local indShortSignal = deadCatSignal == SignalShort
-- MODIFIED: Track last signal timestamps and fill counters for long/short
local lastLongSignalTime = Load('lastLongSignalTime', 0)
local lastShortSignalTime = Load('lastShortSignalTime', 0)
local longFillsThisTrigger = Load('longFillsThisTrigger', 0)
local shortFillsThisTrigger = Load('shortFillsThisTrigger', 0)
local signalWindowSeconds = signalWindowMinutes * 60 -- Convert to seconds for Time() comparison
-- Detect new signals and start/reset windows/counters
if indLongSignal then
lastLongSignalTime = Time()
longFillsThisTrigger = 0 -- Reset on new signal
Save('lastLongSignalTime', lastLongSignalTime)
Save('longFillsThisTrigger', longFillsThisTrigger)
if showInfo then Log('New Long Signal: Starting window') end
end
if indShortSignal then
lastShortSignalTime = Time()
shortFillsThisTrigger = 0
Save('lastShortSignalTime', lastShortSignalTime)
Save('shortFillsThisTrigger', shortFillsThisTrigger)
if showInfo then Log('New Short Signal: Starting window') end
end
-- Check if within signal window (if enabled)
local inLongWindow = okSignalWindow and (Time() - lastLongSignalTime <= signalWindowSeconds) or true -- True if disabled
local inShortWindow = okSignalWindow and (Time() - lastShortSignalTime <= signalWindowSeconds) or true
-- ==================== DYNAMIC SPREAD FUNCTION ====================
local sideBudgetLong = budgetBal / 2
local sideBudgetShort = budgetBal / 2
local longWorkBal = usedLong - getProfitL
local shortWorkBal = usedShort - getProfitS
local function getDynamicSpread(expo)
if expo < 0.1 then return 0.9
elseif expo < 0.2 then return 1.618
elseif expo < 0.3 then return 3
else return 6 end
end
local effectiveSlotSpreadL = slotSpreadL
local effectiveSlotSpreadS = slotSpreadS
local effectiveSlotCancelL = slotCancel
local effectiveSlotCancelS = slotCancel
local effectiveMinSpreadL = minSpreadInput
local effectiveMinSpreadS = minSpreadInput
if okDynamicSpread then
local longExpo = sideBudgetLong > 0 and longWorkBal / sideBudgetLong or 0
local shortExpo = sideBudgetShort > 0 and shortWorkBal / sideBudgetShort or 0
local longDynamic = getDynamicSpread(longExpo)
local shortDynamic = getDynamicSpread(shortExpo)
effectiveSlotSpreadL = longDynamic
effectiveSlotSpreadS = shortDynamic
effectiveSlotCancelL = longDynamic / 3
effectiveSlotCancelS = shortDynamic / 3
effectiveMinSpreadL = longDynamic / 3
effectiveMinSpreadS = shortDynamic / 3
if showInfo then
Log('Long Expo='..Round(longExpo,3)..' → Spread='..longDynamic..'% Cancel='..effectiveSlotCancelL..'% Min='..effectiveMinSpreadL..'%')
Log('Short Expo='..Round(shortExpo,3)..' → Spread='..shortDynamic..'% Cancel='..effectiveSlotCancelS..'% Min='..effectiveMinSpreadS..'%')
end
end
local minSpreadL = effectiveMinSpreadL / 2.0
local minSpreadS = effectiveMinSpreadS / 2.0
-- ==================== SLOT FUNCTION ====================
local slot = function(isLong, index, amount, spread, cancelDist, canPlace)
local prefix = isLong and 'L' or 'S'
local name = prefix .. index
local cmd = isLong and PlaceGoLongOrder or PlaceGoShortOrder
local priceBase = isLong and cp.bid or cp.ask
local minSpr = isLong and minSpreadL or minSpreadS
local spr = Min(averageSpreadPercentage, minSpr) + spread * index
local posId = isLong and hedge_longPosId or hedge_shortPosId
local aep = isLong and aep_l or aep_s
if aep > 0 then
priceBase = isLong and Min(aep, priceBase) or Max(aep, priceBase)
end
local price = isLong and SubPerc(priceBase, spr) or AddPerc(priceBase, spr)
if isBinance then
local notionalSize = 5.1 / price
if amount < notionalSize then amount = notionalSize end
end
local oid = Load(name..'oid', '')
if oid ~= '' then
local order = OrderContainer(oid)
if order.isOpen then
local delta = isLong and Delta(AddPerc(order.price, spr), priceBase) or Delta(priceBase, SubPerc(order.price, spr))
if delta >= cancelDist then
CancelOrder(oid)
LogWarning('Delta cancelled '..name)
elseif not canPlace then
CancelOrder(oid)
LogWarning('Not allowed right now '..name)
end
else
-- MODIFIED: Check for fill and increment counter if filled
if order.isFilled then
if isLong then
longFillsThisTrigger = longFillsThisTrigger + 1
Save('longFillsThisTrigger', longFillsThisTrigger)
if showInfo then Log('Long fill detected for trigger: Count='..longFillsThisTrigger) end
else
shortFillsThisTrigger = shortFillsThisTrigger + 1
Save('shortFillsThisTrigger', shortFillsThisTrigger)
if showInfo then Log('Short fill detected for trigger: Count='..shortFillsThisTrigger) end
end
end
oid = ''
end
else
-- MODIFIED: Add fill limit check before placing
local underFillLimit = isLong and (longFillsThisTrigger < maxFillsPerTrigger) or (shortFillsThisTrigger < maxFillsPerTrigger)
if canPlace and underFillLimit then
oid = cmd(price, amount, {type = MakerOrCancelOrderType, note = name, timeout = 3600, positionId = posId})
elseif not underFillLimit and showInfo then
LogWarning('Max fills per trigger reached for '.. (isLong and 'Long' or 'Short') ..' - Skipping placement')
end
end
Save(name..'oid', oid)
end
-- ==================== TAKE PROFIT & RISK MANAGEMENT ====================
local updateTakeProfit = function(isLong, entryPrice, targetRoi, cancelDist)
local prefix = isLong and 'Long' or 'Short'
local name = prefix .. ' TP'
local oid = Load(prefix..'tp_oid', '')
local timer = Load(prefix..'tp_timer', 0)
local posId = isLong and hedge_longPosId or hedge_shortPosId
local tp_delta = isLong and Delta(entryPrice, cp.bid) or Delta(cp.ask, entryPrice)
if oid ~= '' then
local order = OrderContainer(oid)
if order.isOpen then
local delta = isLong and Delta(order.price, cp.close) or Delta(cp.close, order.price)
if delta >= cancelDist then CancelOrder(oid) end
else
if order.isCancelled then timer = 0 end
oid = ''
end
else
if preplacedTP then
if isLong and pamt_l > 0 and not okSmartTP then
oid = PlaceExitPositionOrder({price = AddPerc(aep_l, takeProfitL), type = tpOrderType, note = 'Pre-Placed '..name, timeout = 200, positionId = hedge_longPosId})
elseif not isLong and pamt_s > 0 and not okSmartTP then
oid = PlaceExitPositionOrder({price = SubPerc(aep_s, takeProfitS), type = tpOrderType, note = 'Pre-Placed '..name, timeout = 200, positionId = hedge_shortPosId})
end
elseif tp_delta >= targetRoi and Time() >= timer and not okSmartTP then
oid = PlaceExitPositionOrder({type = tpOrderType, note = name, timeout = 200, positionId = posId})
timer = Time() + 60
end
end
Save(prefix..'tp_oid', oid)
Save(prefix..'tp_timer', timer)
end
local updatePositionManagement = function(isLong, currentSize, sizeLimit, cancelDist)
local prefix = isLong and 'Long' or 'Short'
local name = prefix .. ' Size Reduction'
local oid = Load(prefix..'pos_oid', '')
local posId = isLong and hedge_longPosId or hedge_shortPosId
local amount = SubPerc(currentSize, 100 - reduceSize)
local price = isLong and cp.ask or cp.bid
local cmd = isLong and PlaceExitLongOrder or PlaceExitShortOrder
local timer = Load(prefix..'pos_timer', Time())
local okReduce = budgetIsolation and (balRatio >= 1) or (currentSize > sizeLimit)
if oid ~= '' then
local order = OrderContainer(oid)
if order.isOpen then
local delta = isLong and Delta(order.price, cp.close) or Delta(cp.close, order.price)
if delta >= cancelDist then CancelOrder(oid) end
elseif order.isFilled then
Save('SRCounter', Load('SRCounter',0) + 1)
oid = ''
else
oid = ''
end
else
if okReduce and not noReduce and Time() >= timer then
oid = cmd(price, amount, {type = reduceOrderType, note = name, timeout = 6000, positionId = posId})
timer = Time() + 60
end
end
Save(prefix..'pos_oid', oid)
Save(prefix..'pos_timer', timer)
end
-- ==================== CORE SLOT UPDATES ====================
updateTakeProfit(true, aep_l, takeProfitL, slotCancel)
updateTakeProfit(false, aep_s, takeProfitS, slotCancel)
updatePositionManagement(true, pamt_l, maxSize, slotCancel)
updatePositionManagement(false, pamt_s, maxSize, slotCancel)
-- Slot refill with gating
-- MODIFIED: Added inLongWindow/inShortWindow to canPlace; removed trend
for r = 1, slotRefillCount do
for i = 1, slotCount do
slot(true, i, slotSizeL, effectiveSlotSpreadL, effectiveSlotCancelL, okLong and canEnterNewTrades and indLongSignal and inLongWindow)
slotSizeL = slotSizeL * slotMultiplier
effectiveSlotSpreadL = effectiveSlotSpreadL * slotSpreadM
end
end
for r = 1, slotRefillCount do
for i = 1, slotCount do
slot(false, i, slotSizeS, effectiveSlotSpreadS, effectiveSlotCancelS, okShort and canEnterNewTrades and indShortSignal and inShortWindow)
slotSizeS = slotSizeS * slotMultiplier
effectiveSlotSpreadS = effectiveSlotSpreadS * slotSpreadM
end
end
-- ==================== WTF & FORCE ====================
if wtfStop and not isLongPosOpen and not isShortPosOpen then DeactivateBot('Deactivate on No Position is active', true) end
if wtfBal and workBal >= budgetBal then DeactivateBot('Over Budget', true) end
if wtfAmount and (pamt_l > maxSize or pamt_s > maxSize) then DeactivateBot('Over Size', true) end
if wtfRatio and balRatio > wtfRatioV then DeactivateBot('Bal Ratio over '..wtfRatioV, true) end
if wtfWallet and walletBal <= 0 then DeactivateBot('Wallet is 0', true) end
if FStop then
PlaceExitPositionOrder({type = reduceOrderType, note = 'Force Exit', timeout = 3600})
end
-- ==================== PLOTS & FINALIZE ====================
if aep_l > 0 then Plot(0, 'AvgEP Long', aep_l, {c=Teal}) end
if aep_s > 0 then Plot(0, 'AvgEP Short', aep_s, {c=Purple}) end
Plot(1, 'Longs', pamt_l, {c=Green, s=Step})
Plot(1, 'Max Longs', maxSize, {c=White, s=Step})
Plot(1, 'Shorts', -pamt_s, {c=Red, s=Step})
Plot(1, 'Max Shorts', -maxSize, {c=White, s=Step})
ChartSetOptions(1, 'Exposure')
Plot(2, 'Budget Balance', budgetBal, {c=White, s=Step})
Plot(2, 'WorkBal', workBal, {c=Red, s=Step})
Plot(2, 'Wallet Balance', walletBal, {c=DarkGreen, s=Step})
ChartSetOptions(2, 'Balance Monitor')
if showInfo then Log('Size Reduction: '..SRCounter..' times') end
if not okLong then LogWarning('Bot is not allowed to open LONG') end
if not okShort then LogWarning('Bot is not allowed to open SHORT') end
Finalize(function()
CustomReport('Final Wallet Balance', Round(walletBal,5)..' '..profitLabel)
CustomReport('Size Reduction', SRCounter..' times')
CustomReport('Highest Balance Ratio', Round(100 * BRCounter,2)..'%')
end)
Save('hedge_longPosId', hedge_longPosId)
Save('hedge_shortPosId', hedge_shortPosId)
if showInfo then Log(' ') end
0 Comments
Sign in to leave a comment.
No comments yet. Be the first!