In questo listato var CONST = {
    ORDER_SIDE: 'BID',
    SIZE: 1,
    MAX_OPERATIONS: 8,
    STAY_AT_LEVEL_BID: 6,
    STAY_AT_LEVEL_ASK: 6,
    SECONDS: 5,
    MONITORING_MODE: 'MONITORA_yourlevel'
};

var separator = "---------------------------------------------------\r\n";

var lookup = {
    BID: { side: 'Bid', level: CONST.STAY_AT_LEVEL_BID },
    ASK: { side: 'Ask', level: CONST.STAY_AT_LEVEL_ASK }
};

function getUpperLowerCaseVariants(str) {
    return {
        upper: str.toUpperCase(),
        lower: str.toLowerCase()
    };
}

var BookUtils = {
    getData: function (book, side, type, level) {
        var sideData = (side === 'Bid') ? book.Bid : book.Ask;
        return type === 'Price' ? sideData.Price(level) : sideData.Quantity(level);
    },
    
    getBookState: function (book) {
        var bid = book.Bid;
        var ask = book.Ask;
		return {
            bidPrice: book.Bid.Price(0),
            bidQuantity: book.Bid.Quantity(0),
            askPrice: book.Ask.Price(0),
            askQuantity: book.Ask.Quantity(0)
        };
    }
};

var OrderUtils = {
    execOrder: function (side, stock, price, size) {
        return side === 'BID' ? OrderManager.Buy(stock, price, size) : OrderManager.Sell(stock, price, size);
    },

    updateOrderContext: function (order, side, price) {
        UserContext.order.current = order;
        var sideVariants = getUpperLowerCaseVariants(side);
        UserContext.prices[sideVariants.lower].oldLevel = price;
        return order;
    },

    processOrModOrder: function (side, stock, price) {
        var currentOrder = getCurrentOrder();
        if (currentOrder && currentOrder.Price === price) {
            return currentOrder;
        }
        var orderToUpdate = currentOrder ? 
            OrderManager.Modify(currentOrder.OrderCode, price) : 
            this.execOrder(side, stock, price, CONST.SIZE);
        return this.updateOrderContext(orderToUpdate, side, price);
    },
    deleteOrder: function (orderCode) {
        return OrderManager.Delete(orderCode);
    }
};

var Helper = {
    cachedPriceDirections: {},

    PriceDirection: function (targetPrice, oldPrice) {
        var key = targetPrice + '_' + oldPrice;
        if (!(key in this.cachedPriceDirections)) {
            this.cachedPriceDirections[key] = targetPrice > oldPrice ? 1 : (targetPrice < oldPrice ? -1 : 0);
        }
        return this.cachedPriceDirections[key];
    },

    formatState: function (bookState) {
        return separator + 
          "Bid Price \tBid Quant.   \tAsk Price \tAsk Quant. \r\n" + separator +
          bookState.bidPrice + "\t\t" + bookState.bidQuantity + "\t\t" + bookState.askPrice + "\t\t" + bookState.askQuantity + "\r\n" +
          separator + "Numero Operazione: " + UserContext.status.numOperazione + "\r\n" + separator;
    },

  log: function (type, data) {
    var message = "";
    if (type === 'action') {
        message = getActionMessage(data.actionType, data.payload) + 
                  Helper.formatState(BookUtils.getBookState(UserContext.book));
    } else if (type === 'message') {
        message = data + "\r\n" + separator;
    } else if (type === 'priceChange') {
        message = formatPriceChange(data);
    }
    Log(separator + message);
}
};

function getActionMessage(actionType, data) {
    switch (actionType) {
        case "Initialization Complete":
            return "Inizializzazione completata: \nBid Price 0: " + UserContext.prices.bid.current + 
                   "\nAsk Price 0: " + UserContext.prices.ask.current + "\n";
        case "Order Action":
            return 'Ordine ' + data.action + ': ' + data.order.OrderCode + "\n";
        case "Price Variation":
            return 'Livello da ' + data.lastLevel + " all'attuale livello " + data.priceLevel + "\n";
        case "Order Deleted":
            return 'Ordine cancellato: ' + data.order.OrderCode + "\n";
        default:
            return "";
    }
}

function formatPriceChange(data) {
    return "ULTIMO PREZZO: " + data.currentPrice + ", " +
           "Precedente: " + data.previousPrice + ", " +
           "Ora: " + data.currentTime + "\r\n" + separator;
}

function getCurrentOrder() {
    return UserContext.order.current;
}

function InitializeTradeContext(book) {
    var initialPrices = {
        bid: BookUtils.getData(book, 'Bid', 'Price', 0),
        ask: BookUtils.getData(book, 'Ask', 'Price', 0)
    };
    
    this.book = book;
    this.order = { current: null, modified: false };
    this.status = { run: true, secondCount: 0, numOperazione: 1 };
    this.prices = { 
        bid: { current: initialPrices.bid, oldLevel: 0 }, 
        ask: { current: initialPrices.ask, oldLevel: 0 } 
    };
    this.initialPriceLevel = lookup[CONST.ORDER_SIDE].level;
}

function getTargetPriceLevel(sideUpper, priceLevel) {
    return (CONST.MONITORING_MODE === 'MONITORA_1level' ? priceLevel : lookup[sideUpper].level) - 1;
}

function PriceUpdate(side, book, priceLevel) {
    var sideVariants = getUpperLowerCaseVariants(side);
    var priceData = UserContext.prices[sideVariants.lower];
    var lookupData = lookup[sideVariants.upper];
    var targetPriceLevel = getTargetPriceLevel(sideVariants.upper, priceLevel);
    var targetPrice = BookUtils.getData(book, lookupData.side, 'Price', targetPriceLevel);
    var oldPrice = priceData.oldLevel;

    if (targetPrice !== oldPrice) {
        var newOrder = OrderUtils.processOrModOrder(sideVariants.upper, stock, targetPrice);
        if (newOrder) {
            priceData.current = targetPrice;

            Helper.log('action', { 
                actionType: "Price Variation", 
                payload: { 
                    order: newOrder, 
                    lastLevel: priceLevel + Helper.PriceDirection(targetPrice, oldPrice), 
                    priceLevel: targetPriceLevel 
                }
            });
            UserContext.status.secondCount = 0;
            UserContext.status.numOperazione++;
        }
    }
}

function DetectPriceChange(side, book) {
    var sideVariants = getUpperLowerCaseVariants(side);
    PriceUpdate(sideVariants.upper, book, lookup[sideVariants.upper].level);
}

function checkOps() {
    var status = UserContext.status;
    var currentOrder = getCurrentOrder();
    if (status.numOperazione >= CONST.MAX_OPERATIONS && currentOrder) {
        var deletedOrder = OrderUtils.deleteOrder(currentOrder.OrderCode);
        Helper.log('action', { 
            actionType: "Order Deleted", 
            payload: { order: deletedOrder } 
        });
        status.run = false;
        return true;
    }
    return false;
}

function ManageCycle(priceLevel) {
    var status = UserContext.status;
    if (!status.run) return;
    if (checkOps()) return;
    var shouldDetect = (status.secondCount >= CONST.SECONDS) || (typeof priceLevel !== 'undefined');
    if (shouldDetect) {
        DetectPriceChange(CONST.ORDER_SIDE, UserContext.book);
    }
}

function SetupTradeContext() {
    var book = Book(ps);
    UserContext = new InitializeTradeContext(book);
    Helper.log('action', { 
        actionType: "Initialization Complete", 
        payload: null 
    });
    ManageCycle(UserContext.initialPriceLevel);
}

function MarketEvent() {
    if (!UserContext.status.run) return;
    var eventType = SystemContext.EventType;
    var book = UserContext.book || Book(ps);
    UserContext.book = book;
    
    switch(eventType) {
        case TSEventType.Time:
            UserContext.status.secondCount++;
            ManageCycle();
            break;
        case TSEventType.Price:
            var currentPrice = Val(ps, "LAST");
            if (UserContext.lastPrice !== currentPrice) {
                var currentTime = Now().ToString("HH:mm:ss.ff");
                Helper.log('priceChange', { 
                    currentPrice: currentPrice, 
                    previousPrice: UserContext.lastPrice, 
                    currentTime: currentTime 
                });
                UserContext.lastPrice = currentPrice;
            }
            break;
    }
}

if (SystemContext.IsFirst) {
    SetupTradeContext();
}

MarketEvent(); converrebbe utilizzare un oggetto di configurazione per le costanti invece di variabili globali? Me lo consiglieresti o no ?