Description
Execute command for FEBE.
More information about FEBE: https://www.haasscripts.com/blog/guides/first-ever-bot-engine-febe-for-haasscript/
HaasScript
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)
0 Comments
Sign in to leave a comment.
No comments yet. Be the first!