[FEBE] Execute

0 154 Views No Comments 3 weeks ago
  • Execute command for FEBE.

    More information about FEBE: https://www.haasscripts.com/blog/guides/first-ever-bot-engine-febe-for-haasscript/

    HaasScript Code
    DefineCommand('FEBE_Execute', 'Execute FEBE logic with parameters')
    
    local p = DefineParameter(ListDynamicType, 'params', 'Parameters for the core logic', true, {})
    
    -- setup trading commands
    local cmd_enterLong, cmd_enterShort
    local cmd_exitPosition = PlaceExitPositionOrder
    if MarketType() == SpotTrading then
        cmd_enterLong = PlaceBuyOrder
        cmd_enterShort = PlaceSellOrder
    else
        cmd_enterLong = PlaceExitShortOrder
        cmd_enterShort = PlaceExitLongOrder
    end
    
    -- position information
    local pos = {
        dir = GetPositionDirection(),
        aep = GetPositionEnterPrice(),
        amt = GetPositionAmount()
    }
    
    -- price information
    local cp = CurrentPrice()
    
    -- supported modules array
    local supported_modules = {
        's_orders',
        's_tp',
        's_sl',
        's_buy',
        's_sell',
    }
    
    -- init active modules
    local active_modules = {}
    for i = 1, #supported_modules do
        active_modules[ supported_modules[i] ] = false
    end
    
    
    -- log with prefix
    local log = function(msg)
        Log('[FEBE] ' .. msg)
    end
    
    -- log warning with prefix
    local warn = function(msg)
        LogWarning('[FEBE] ' .. msg)
    end
    
    -- log error with prefix
    local error = function(msg)
        LogError('[FEBE] ' .. msg)
    end
    
    
    -- update order bundle (buy/sell entries)
    local updateOrderBundle = function(isLong, id, settings)
        local active = settings.active
    
        for i = 1, settings.order_count do
            local name = id .. i
            local oid = Load(name .. 'oid', '')
            local place_price = Load(name .. 'pp', 0)
            local filled = Load(name .. 'f', false)
    
            if oid != '' then
                local order = OrderContainer(oid)
                
                if order.isOpen then
                    local delta = -1
                    local max_dist = active and settings.order_cancel_dist or 0
                    
                    -- only calculate delta if cancel distance is used
                    if max_dist > 0 then
                        delta = isLong
                            and Delta(cp.close, place_price)
                            or Delta(place_price, cp.close)
                    end
                    
                    if not active then
                        CancelOrder(oid)
                        Log('Deactivated '..name)
                    elseif delta >= settings.order_cancel_dist then
                        CancelOrder(oid)
                        Log('Delta cancelled '..name..' (delta: '..Round(delta, 4)..' %)')
                    end
                else
                    oid = ''
    
                    if order.filledAmount > 0 then
                        filled = true
                    end
                end
            else
                if active then
                    if not filled or settings.order_refill then
                        -- select trading command
                        local cmd = isLong and cmd_enterLong or cmd_enterShort
    
                        -- order settings
                        local order_settings = {
                            type = CC_FEBE_ParseOrderType(settings.order_type),
                            note = name,
                            timeout = settings.order_timeout
                        }
    
                        -- order price with spread
                        local offset = settings.order_spread * i
                        local price = isLong
                                and SubPerc(cp.close, offset)
                                or AddPerc(cp.close, offset)
                        
                        -- order size
                        local amount = settings.order_size
    
                        -- place order
                        oid = cmd(price, amount, order_settings)
    
                        -- save price for cancel threshold calcs
                        place_price = cp.close
                    end
                else
                    -- reset
                    filled = false
                    place_price = 0
                end
            end
    
    
            Save(name .. 'oid', oid)
            Save(name .. 'pp', place_price)
            Save(name .. 'f', filled)
        end
    end
    
    -- update exit order
    local updateExitOrder = function(id, note, price, type, active)
        local oid = Load(id .. 'oid', '')
    
        if oid == '' then
            if active then
                local settings = {
                    type = CC_FEBE_ParseOrderType(type),
                    note = note,
                    timeout = 9999999
                }
    
                local isLong = pos.dir == PositionLong
                local cmd = isLong and cmd_enterShort or cmd_enterLong
    
                oid = cmd(price, pos.amt, settings)
            end
        else
            local order = OrderContainer(oid)
    
            if order.isOpen then
                if not active then
                    CancelOrder(oid)
                    Log('Deactivated '..note)
                
                elseif order.executedAmount != pos.amt then
                    CancelOrder(oid)
                    Log('Refreshing order size for '..note)
    
                elseif order.price != price then
                    CancelOrder(oid)
                    Log('Refreshing order price for '..note)
                end
            else
                oid = ''
            end
        end
    
        Save(id .. 'oid', oid)
    end
    
    
    -- pre-process parameters
    local params = {}
    local plen = #p
    local key = ''
    local value
    for i = 1, plen do
        key = p[i][1]
        value = p[i][2]
    
        params[ key ] = {}
    
        -- build section parameters
        if value != nil then
            local vlen = #value
            for j = 1, vlen do
                params[ key ][ value[j][1] ] = value[j][2] 
            end
        end
    
        active_modules[ key ] = true
    
        Log( params[key] )
    end
    
    ----------------------------  MODULES  ------------------------------
    --    Module functionality should be placed below these lines!     --
    ---------------------------------------------------------------------
    
    -- pre-define required variables
    local orders = {}
    local module = {}
    module.name = supported_modules[1]
    module.max_open = 'max_open'
    module.size = 'size'
    module.spread = 'spread'
    module.cancel_dist = 'cancel_dist'
    
    if active_modules[ module.name ] == true then
        log('Found order settings')
    
        local module_params = params[ module.name ]
    
        -- grab order settings
        orders.max_open     = module_params[ module.max_open ]
        orders.size         = module_params[ module.size ]
        orders.spread       = module_params[ module.spread ]
        orders.cancel_dist  = module_params[ module.cancel_dist ]
    
    else
        -- setup 1 order and use main TradeAmount()
        orders.max_open = 1
        orders.size = TradeAmount()
        orders.spread = 0
        orders.cancel_dist = 0
    end
    
    ---------------------------------------------------------------------
    -- setup take-profit
    module = {}
    module.name = supported_modules[2]
    module.percent = 'percent'
    module.order_type = 'order_type'
    
    if active_modules[ module.name ] == true then
        log('Found take-profit settings')
    
        local module_params = params[ module.name ]
    
        -- grab settings
        local tp = {}
        tp.percent          = module_params[ module.percent ]
        tp.order_type       = module_params[ module.order_type ]
        tp.active           = false
        tp.price            = 0
    
        -- if using market order, wait for trigger
        if tp.order_type == 2 then
            if TakeProfit(tp.percent) then
                tp.active = true
                tp.price = cp.close -- price isnt important for market orders
            end
    
        -- if using other than stop orders, we can place it immediately
        elseif tp.order_type <= 4 or tp.order_type >= 7 then
            -- place TP beforehand
            tp.active = true
            
            -- calculate trigger price
            if pos.dir == PositionLong then
                tp.price = AddPerc( pos.aep, tp.percent )
            elseif pos.dir == PositionShort then
                tp.price = SubPerc( pos.aep, tp.percent )
            end
        else
            error('Native Stop order types not supported for Take-Profit')
            tp.active = false
        end
    
        -- if we got a price, parse it properly
        if tp.price > 0 then
            tp.price = ParseTradePrice(PriceMarket(), tp.price)
        end
    
        tp.active = tp.active and pos.dir != NoPosition
    
        -- run
        updateExitOrder('tp', 'Take-Profit', tp.price, tp.order_type, tp.active)
    end
    
    ---------------------------------------------------------------------
    -- setup stop-loss
    module.name = supported_modules[3]
    
    if active_modules[ module.name ] == true then
        log('Found stop-loss settings')
    
        local module_params = params[ module.name ]
    
        -- grab settings
        local sl = {}
        sl.percent          = module_params[ module.percent ]
        sl.order_type       = module_params[ module.order_type ]
        sl.active           = false
        sl.price            = 0
    
        -- regular order types
        if sl.order_type <= 4 then
            -- wait until percent price change and place order
            if StopLoss(sl.percent) then
                sl.active = true
                
                if pos.dir == PositionLong then
                    sl.price = cp.ask
                elseif pos.dir == PositionShort then
                    sl.price = cp.bid
                end
            end
    
        -- native stop types
        elseif sl.order_type > 4 and sl.order_type < 7 then
            -- place SL beforehand when using native stops
            sl.active = true
    
            -- calculate trigger price
            if pos.dir == PositionLong then
                sl.price = SubPerc( pos.aep, sl.percent )
            elseif pos.dir == PositionShort then
                sl.price = AddPerc( pos.aep, sl.percent )
            end
        else
            error('Native Take-Profit order types not supported for Stop-Loss')
        end
    
        -- if we got a price, parse it properly
        if sl.price > 0 then
            sl.price = ParseTradePrice(PriceMarket(), sl.price)
        end
    
        sl.active = sl.active and pos.dir != NoPosition
    
        -- run
        updateExitOrder('sl', 'Stop-Loss', sl.price, sl.order_type, sl.active)
    end
    
    ---------------------------------------------------------------------
    -- setup and run buying
    module = {}
    module.name = supported_modules[4]
    module.order_timeout = 'order_timeout'
    module.order_refill = 'order_refill'
    module.order_type = 'order_type'
    
    if active_modules[ module.name ] == true then
        log('Found buy settings')
    
        local module_params = params[ module.name ]
    
        -- grab settings
        local buy = {}
        buy.active = true
        buy.order_timeout       = module_params[ module.order_timeout ]
        buy.order_refill        = module_params[ module.order_refill ]
        buy.order_type          = module_params[ module.order_type ]
        buy.order_count         = orders.max_open
        buy.order_size          = orders.size
        buy.order_spread        = orders.spread
        buy.order_cancel_dist   = orders.cancel_dist
    
        -- update orders with buy settings
        updateOrderBundle( true, 'buy', buy )
        
    else
        -- grab settings
        local buy = {}
        buy.active = false
        buy.order_count         = orders.max_open
    
        -- cancel all open orders and reset
        updateOrderBundle( true, 'buy', buy )
    end
    
    ---------------------------------------------------------------------
    -- setup and run selling
    module.name = supported_modules[5]
    
    if active_modules[ module.name ] == true then
        log('Found sell settings')
    
        local module_params = params[ module.name ]
    
        -- grab settings
        local sell = {}
        sell.active = true
        sell.order_timeout       = module_params[ module.order_timeout ]
        sell.order_refill        = module_params[ module.order_refill ]
        sell.order_type          = module_params[ module.order_type ]
        sell.order_count         = orders.max_open
        sell.order_size          = orders.size
        sell.order_spread        = orders.spread
        sell.order_cancel_dist   = orders.cancel_dist
    
        -- update orders with sell settings
        updateOrderBundle( false, 'sell', sell )
        
    else
        -- grab settings
        local sell = {}
        sell.active = false
        sell.order_count         = orders.max_open
    
        -- cancel all open orders and reset
        updateOrderBundle( false, 'sell', sell )
    end
    
    
    ---------------------------------------------------------------------
    -- plot position information on the chart
    if pos.dir != NoPosition then
        local pc = PositionContainer()
        local id = pc.positionId
        local isLong = pos.dir == PositionLong
    
        -- position average entry price
        Plot(0, 'pos.aep', pos.aep, LineOptions({color = Cyan, id = id}))
    
        -- position size
        Plot(-2, 'pos.amt', pos.amt, LineOptions({color = isLong and Green or Red, id = id}))
    
        -- position profit
        Plot(-3, 'pos.profit', pc.profit, LineOptions({color = isLong and Green or Red, id = id}))
    
        -- position roi
        Plot(-3, 'pos.roi', pc.roi, LineOptions({color = isLong and Cyan or Fuchsia, id = id, side = LeftAxis}))
    
        -- zeron-lines for profit and roi
        PlotHorizontalLine(-3, '', White(50), 0, Dashed, RightAxis)
        PlotHorizontalLine(-3, '', White(50), 0, Dotted, LeftAxis)
    end
    
    
    
    
    ---------------------------------------------------------------------
    DefineOutput(VoidType)
Login or Register to Comment

Unlock your crypto trading potential

Create a free account and enjoy everything we have to offer.

Join for Free