[bot] Signal Trigger with Multiple Positions
stableDescription
Basic bot/template for managing multiple positions and single order per position with stoploss and take profit
Get a signal from where ever you like either from another script or remote signal and it will manage multiple positions both long and short.
Requires my other custom commands to work -
[cmd] GetPID (getPositionId)
[cmd] getOID
[cmd] CheckOpenOrder
[cmd]CheckPositionId
— Author – Strooth – Find me on discord – strooth#4739
— Feel free to donate to support my work or if my script helped you in any way <3
— BTC Adress: 33MsEAbA8tg7SpohgnCpSrmPTBih2UkhxQ
—
HaasScript
— Author – Strooth – Find me on discord – strooth#4739
— Feel free to donate to support my work or if my script helped you in any way <3
— BTC Adress: 33MsEAbA8tg7SpohgnCpSrmPTBih2UkhxQ
—
InputGroupHeader('Main')
local allowshort = Input('Enable Short', true, 'Enable short positions')
local allowlong = Input('Enable Long', true, 'Enable long positions')
local allowshortx = Input('Enable Short Reduce', true, 'Enable short positions reduction/exits')
local allowlongx = Input('Enable Long Reduce', true, 'Enable long positions reduction/exits')
InputGroupHeader('Settings')
local positionlimit = Input('Position Limit', 1, 'The number of positions to use per side')
local spread = Input('Spread', 1, 'The percentage spread each position order should be aawy from each other')
local xdivs = Input('Exit Divider Short', 1.5, 'The amount to divide the trade amount on reduce orders')
local xdivl = Input('Exit Divider Long', 2, 'The amount to divide the trade amount on reduce orders')
local takeprofit = Input('Take Profit', 100, 'The take profit in ROI to use')
local mintakeprofit = Input('Min Take Profit', 20, 'The minimum take profit to use if signal exit position is triggered')
local usestop = Input('Enable Stop Loss', false, 'Enable using stop loss')
local stoploss = Input('Stop Loss', 20, 'The stop loss percent of the positions')
-- Get a signal from somewhere
--local signal = GetRemoteSignal(NewGuid())
local signal = EasyDynamicLongShortLevels(0)
local longsignal = IfElseIf(signal==SignalLong, signal==SignalShort, signal, SignalExitLong, signal)
local shortsignal = IfElseIf(signal==SignalShort, signal==SignalLong, signal, SignalExitShort, signal)
--- Get Price
local cp = CurrentPrice()
---
-- Cancel all orders function
local cancel = function(pid)
if IsAnyOrderOpen(pid) then
CancelAllOrders(pid)
end
end
--- Get order price function
local getprice = function(isLong, isExit, index)
local out = cp.close
if isLong == true then
if isExit == true then
out = LastExitLongPrice() == 0 and cp.high or AddPerc(Max(LastExitLongPrice(), cp.high), spread*index)
else
out = LastLongPrice() == 0 and cp.low or SubPerc(Min(LastLongPrice(), cp.low), spread*index)
end
elseif isLong == false then
if isExit == true then
out = LastExitShortPrice() == 0 and cp.low or SubPerc(Min(LastExitShortPrice(), cp.low), spread*index)
else
out = LastShortPrice() == 0 and cp.high or AddPerc(Max(LastShortPrice(), cp.high), spread*index)
end
end
return out
end
--- Check percentage change function
local checkdelta = function(isLong, price, distance)
if price == 0 then
return true
else
local cp = Switch(isLong==true, cp.ask, cp.bid)
local _price = Switch(isLong==true, SubPerc(price, distance), AddPerc(price, distance))
local out = Switch(isLong==true, IsSmallerThan(cp, _price), IsBiggerThan(cp, _price))
return out
end
end
--- exit position function
local ExitPos = function(PosId, side, index, orderparams)
-- cancel any existing open orders for this position befor placing a new one
cancel(PosId)
-- update params
orderparams.positionId = PosId
-- save new order id
CC_getOID(side, index, PlaceExitPositionOrder(orderparams))
end
-- bot logic
for k=1, positionlimit do
---- Load PositionId's Per Side and Per Index (If Position Limit == 10 then loops through 10 times for each side which means it will check 10 short positions and 10 long positions per interval)
---- If you just want to keep it simple to 1 position per side i.e. 1 long and 1 short open then set position limit to 1
local params = {positionId = '', market = PriceMarket(), type = GetOrderType(), note = ''}
local ShortPosId = CC_getPID(false, k)
local ShortOID = CC_getOID(false, k)
local LongPosId = CC_getPID(true, k)
local LongOID = CC_getOID(true, k)
---- Enter/Reduce
if allowshort then
if And(ShortOID == '', shortsignal == SignalShort, checkdelta(false, Max(LastShortPrice(), GetPositionEnterPrice(ShortPosId)), spread*k)) then
params.positionId = ShortPosId; params.note = 'Go Short - '..ShortPosId; params.reduceOnly = false
CC_getOID(false, k, PlaceGoShortOrder(getprice(false, false, k), TradeAmount(), params))
elseif And(allowshortx, ShortOID == '', shortsignal == SignalExitShort, checkdelta(true, Min(LastExitShortPrice(), GetPositionEnterPrice(ShortPosId)), spread*k)) then
params.positionId = ShortPosId; params.note = 'Exit Short - '..ShortPosId; params.reduceOnly = true
CC_getOID(false, k, PlaceExitShortOrder(getprice(false, true, k), TradeAmount()/xdivs, params))
end
end
if allowlong then
if And(LongOID == '', longsignal == SignalLong, checkdelta(true, Min(LastLongPrice(), GetPositionEnterPrice(LongPosId)), spread*k)) then
params.positionId = LongPosId; params.note = 'Go Long - '..LongPosId; params.reduceOnly = false
CC_getOID(true, k, PlaceGoLongOrder(getprice(true, false, k), TradeAmount(), params))
elseif And(allowlongx, LongOID == '', longsignal == SignalExitLong, checkdelta(false, Max(LastExitLongPrice(), GetPositionEnterPrice(LongPosId)), spread*k)) then
params.positionId = LongPosId; params.note = 'Exit Long - '..LongPosId; params.reduceOnly = true
CC_getOID(true, k, PlaceExitLongOrder(getprice(true, true, k), TradeAmount()/xdivl, params))
end
end
-- Signal Exit
if signal == SignalExitPosition then
if GetPositionROI(ShortPosId) > mintakeprofit then
params.price = getprice(false, true, k); params.note = 'Close Short Position - '..ShortPosId
ExitPos(ShortPosId, false, k, params)
end
if GetPositionROI(LongPosId) > mintakeprofit then
params.price = getprice(true, true, k); params.note = 'Close Long Position - '..LongPosId
ExitPos(LongPosId, true, k, params)
end
else
-- Check for Take Profit and Stop Loss
local shortprofit, shortstop, longprofit, longstop = Load('shortprofit'..ShortPosId, false), Load('shortstop'..ShortPosId, false), Load('longprofit'..LongPosId, false), Load('longstop'..LongPosId, false)
-- Long Exits
if TakeProfitROI(takeprofit, LongPosId) then
longprofit = true
params.note = 'Take Profit on Long Position - '..LongPosId
elseif usestop and StopLoss(stoploss, LongPosId) then
longstop = true
params.note = 'Stop Loss on Long Position - '..LongPosId
end
if longstop then
ExitPos(LongPosId, true, k, params)
elseif longprofit then
if CC_ProfitTrailer(takeprofit, takeprofit, {positionId = LongPosId}) then
ExitPos(LongPosId, true, k, params)
end
end
-- Short Exits
if TakeProfitROI(takeprofit, ShortPosId) then
shortprofit = true
params.note = 'Take Profit on Short Position - '..ShortPosId
elseif usestop and StopLoss(stoploss, ShortPosId) then
shortstop = true
params.note = 'Stop Loss on Short Position - '..ShortPosId
end
if shortstop then
ExitPos(ShortPosId, false, k, params)
elseif shortprofit then
if CC_ProfitTrailer(takeprofit, takeprofit, {positionId = ShortPosId}) then
ExitPos(ShortPosId, false, k, params)
end
end
Save('shortprofit'..ShortPosId, shortprofit)
Save('shortstop'..ShortPosId, shortstop)
Save('longprofit'..LongPosId, longprofit)
Save('longstop'..LongPosId, longstop)
end
end
--- profitz
7 Comments
Sign in to leave a comment.
Thank you for sharing this, I've been tinkering with something similar to no avail. I keep breaching my maxPosi. I set it equal to the net of my two open positions (buys/sells). Was wondering how to tru-up to the exchange periodically to ensure that there is no position drift, would you have anything that can help with that => I found sync_positions but haven't been able to get it working (that was about a month ago so am more proficient with the code.
I am using one of firetron's dca models and trying to stop when I reach a certain "maxPosi". I've inserted the following in Exit() and Go() as described below. for some reason doesn't seem that efficient.
Bot Description:
-- Firetron's Hedged DCA Dipper
--
-- Runs a long and a short each doing dollar cost averaging strategy.
-- Expands positions on an interval and exits whenever there is a profit.
-- Only expands a position when its profit is less than a trigger.
Add's
netPos = (LongAmount() - ShortAmount())
if netPos < 0 and Abs(netPos) > maxPosi then
ExitCheckShort(debugInfo)
elseif netPos > 0 and netPos > maxPosi then
ExitCheckLong(debugInfo)
else
end
Code Blocks Updated
-- ------------------------------------
-- Exiting
-- ------------------------------------
function Exit ()
local debugInfo = GetDebugInfo()
netPos = (LongAmount() - ShortAmount())
if netPos < 0 and Abs(netPos) > maxPosi then
ExitCheckShort(debugInfo)
elseif netPos > 0 and netPos > maxPosi then
ExitCheckLong(debugInfo)
else
end
ExitCheckShort(debugInfo)
ExitCheckShort(debugInfo)
end
Second Spot
function Go ()
local debugInfo = GetDebugInfo()
if debugInfo.isVerbose then
SafeLog(logHRule)
end
netPos = (LongAmount() - ShortAmount())
if netPos < 0 and Abs(netPos) > maxPosi then
ExitCheckShort(debugInfo)
elseif netPos > 0 and netPos > maxPosi then
ExitCheckLong(debugInfo)
else
end
GoCheckLong(debugInfo)
GoCheckShort(debugInfo)
end
Thank you again for this- enlightening. What is the 'index' referencing in your HS?
find me on the Haas Discord channel and pm me for help
strooth#4739
Another great script! Thanks!
When using the script Signal Trigger with Multiple Positions, an error occurs on Binance:
WARNING: Order has failed to execute. Reason: Parameter 'reduceOnly' sent when not required. (Exchange error code: -1106)
Tell me please, I just need to remove the only parameter in the code or replace it with another one, because is it really not possible to place orders with reduce only on binance in the web version?
Here is the piece of code:
if allowshort then
if And(ShortOID == '', shortsignal == SignalShort, checkdelta(false, Max(LastShortPrice(), GetPositionEnterPrice(ShortPosId)), spreadk)) then
params.positionId = ShortPosId; params.note = 'Go Short - '..ShortPosId; params.reduceOnly = false
CC_getOID(false, k, PlaceGoShortOrder(getprice(false, false, k), TradeAmount(), params))
elseif And(allowshortx, ShortOID == '', shortsignal == SignalExitShort, checkdelta(true, Min(LastExitShortPrice(), GetPositionEnterPrice(ShortPosId)), spreadk)) then
params.positionId = ShortPosId; params.note = 'Exit Short - '..ShortPosId; params.reduceOnly = true
CC_getOID(false, k, PlaceExitShortOrder(getprice(false, true, k), TradeAmount()/xdivs, params))
end
end
if allowlong then
if And(LongOID == '', longsignal == SignalLong, checkdelta(true, Min(LastLongPrice(), GetPositionEnterPrice(LongPosId)), spreadk)) then
params.positionId = LongPosId; params.note = 'Go Long - '..LongPosId; params.reduceOnly = false
CC_getOID(true, k, PlaceGoLongOrder(getprice(true, false, k), TradeAmount(), params))
elseif And(allowlongx, LongOID == '', longsignal == SignalExitLong, checkdelta(false, Max(LastExitLongPrice(), GetPositionEnterPrice(LongPosId)), spreadk)) then
params.positionId = LongPosId; params.note = 'Exit Long - '..LongPosId; params.reduceOnly = true
CC_getOID(true, k, PlaceExitLongOrder(getprice(true, true, k), TradeAmount()/xdivl, params))
end
Script error.What should i change here?Where to copy and paste CC_getPID and CC_getOID scripts?
ERROR: - CC_getPID
ERROR: - CC_getOID
ERROR: Unknown references:
Finally I figure out. You need to create custom scripts to work properly.
Can you write settings for this bot?