// custom_blocks.js // Define custom Blockly blocks and JSON code generation export function defineCustomBlocks() { // Register a new type for dynamic values if not already defined Blockly.Types = Blockly.Types || {}; Blockly.Types.DYNAMIC_VALUE = 'dynamic_value'; // Generate dropdown options based on available data const timeframeOptions = bt_data.intervals.map(interval => [interval, interval]); const exchangeOptions = window.UI.exchanges.connected_exchanges.map(exchange => [exchange, exchange]); const symbolOptions = bt_data.symbols.map(symbol => [symbol, symbol]); /************************************************ * VALUE BLOCKS * ************************************************/ /** * last_candle_value * Retrieves a specific part of the last candle (Open, High, Low, Close) from a given source. */ Blockly.defineBlocksWithJsonArray([{ "type": "last_candle_value", "message0": "Last candle %1 value (Src): %2", "args0": [ { "type": "field_dropdown", "name": "candle_part", "options": [ ["Open", "open"], ["High", "high"], ["Low", "low"], ["Close", "close"] ] }, { "type": "input_value", "name": "source", "check": "source" } ], "inputsInline": true, "output": "dynamic_value", "colour": 230, "tooltip": "Retrieve the specified part of the last candle from the given source.", "helpUrl": "" }]); /** * strategy_profit_loss * Evaluates the total strategy's profit or loss. */ Blockly.defineBlocksWithJsonArray([{ "type": "strategy_profit_loss", "message0": "Total Strategy %1 %2", "args0": [ { "type": "field_dropdown", "name": "METRIC", "options": [ ["profit", "profit"], ["loss", "loss"] ] }, { "type": "input_value", "name": "NEXT", "check": "dynamic_value" } ], "inputsInline": true, "output": "dynamic_value", "colour": 230, "tooltip": "Choose to evaluate the strategy's profit or loss.", "helpUrl": "" }]); /** * current_balance * Retrieves the current balance of the strategy. */ Blockly.defineBlocksWithJsonArray([{ "type": "current_balance", "message0": "Current Balance %1", "args0": [ { "type": "input_value", "name": "NEXT", "check": "dynamic_value" } ], "output": "dynamic_value", "colour": 230, "tooltip": "Retrieve the current balance of the strategy.", "helpUrl": "" }]); /** * starting_balance * Retrieves the starting balance of the strategy. */ Blockly.defineBlocksWithJsonArray([{ "type": "starting_balance", "message0": "Starting Balance %1", "args0": [ { "type": "input_value", "name": "NEXT", "check": "dynamic_value" } ], "output": "dynamic_value", "colour": 230, "tooltip": "Retrieve the starting balance of the strategy.", "helpUrl": "" }]); /** * active_trades * Gets the number of active trades currently open. */ Blockly.defineBlocksWithJsonArray([{ "type": "active_trades", "message0": "Number of active trades %1", "args0": [ { "type": "input_value", "name": "NEXT", "check": "dynamic_value" } ], "output": "dynamic_value", "colour": 230, "tooltip": "Get the number of active trades currently open.", "helpUrl": "" }]); /** * math_operation * Performs basic arithmetic operations between two values. */ Blockly.defineBlocksWithJsonArray([{ "type": "math_operation", "message0": "%1 %2 %3", "args0": [ { "type": "input_value", "name": "left", "check": ["number", "dynamic_value"] }, { "type": "field_dropdown", "name": "operator", "options": [ ["+", "ADD"], ["-", "SUBTRACT"], ["*", "MULTIPLY"], ["/", "DIVIDE"] ] }, { "type": "input_value", "name": "right", "check": ["number", "dynamic_value"] } ], "inputsInline": true, "output": "dynamic_value", "colour": 160, "tooltip": "Perform basic arithmetic operations.", "helpUrl": "" }]); /** * value_input * Allows users to input numerical values and chain multiple values for list creation. */ Blockly.defineBlocksWithJsonArray([ { "type": "value_input", "message0": "Value %1 %2", "args0": [ { "type": "field_number", "name": "VALUE", "value": 0, "min": 0 }, { "type": "input_value", "name": "NEXT", "check": "dynamic_value" // Accepts single or list of values } ], "output": "dynamic_value", // Custom type to handle single or list "colour": 330, "tooltip": "Enter a numerical value. Chain multiple for a list.", "helpUrl": "" } ]); /** * source * Defines the data source with Time Frame (TF), Exchange (Ex), and Symbol (Sym). * Use with last_candle_value or any block that returns exchange related values. */ Blockly.defineBlocksWithJsonArray([{ "type": "source", "message0": "src: TF %1 Ex %2 Sym %3", "args0": [ { "type": "field_dropdown", "name": "TF", "options": timeframeOptions }, { "type": "field_dropdown", "name": "EXC", "options": exchangeOptions }, { "type": "field_dropdown", "name": "SYM", "options": symbolOptions } ], "output": "source", // Allows connection to blocks expecting a 'source' type "colour": 230, "tooltip": "Choose the data feed source for the trade or value.", "helpUrl": "" }]); /************************************************ * LOGICAL BLOCKS * ************************************************/ /** * logical_and * Performs a logical AND operation between two Boolean conditions. */ Blockly.defineBlocksWithJsonArray([{ "type": "logical_and", "message0": "%1 AND %2", "args0": [ { "type": "input_value", "name": "left", "check": "Boolean" }, { "type": "input_value", "name": "right", "check": "Boolean" } ], "inputsInline": true, "output": "Boolean", "colour": 210, "tooltip": "Logical AND of two conditions.", "helpUrl": "" }]); /** * logical_or * Performs a logical OR operation between two Boolean conditions. */ Blockly.defineBlocksWithJsonArray([{ "type": "logical_or", "message0": "%1 OR %2", "args0": [ { "type": "input_value", "name": "left", "check": "Boolean" }, { "type": "input_value", "name": "right", "check": "Boolean" } ], "inputsInline": true, "output": "Boolean", "colour": 210, "tooltip": "Logical OR of two conditions.", "helpUrl": "" }]); /** * is_false * Checks if a given Boolean condition is false. */ Blockly.defineBlocksWithJsonArray([{ "type": "is_false", "message0": "%1 is false", "args0": [ { "type": "input_value", "name": "condition", "check": "Boolean" } ], "output": "Boolean", "colour": 160, "tooltip": "Checks if the condition is false.", "helpUrl": "" }]); /************************************************ * TRADE ORDER BLOCKS * ************************************************/ /** * trade_action * Executes a trade action (Buy/Sell) based on a Boolean condition, specifying the amount and optional trade options. */ Blockly.defineBlocksWithJsonArray([ { "type": "trade_action", "message0": "if %1 then %2 amount %3 %4 (Options) %5", "args0": [ { "type": "input_value", "name": "condition", "check": "Boolean" }, { "type": "field_dropdown", "name": "tradeType", "options": [ ["Buy", "buy"], ["Sell", "sell"] ] }, { "type": "input_value", "name": "size", "check": "dynamic_value" // Accepts single value or list }, { "type": "input_statement", "name": "trade_options", "check": "trade_option" }, { "type": "field_dummy" // Placeholder for alignment } ], "previousStatement": null, "nextStatement": null, "colour": 230, "tooltip": "Executes a trade with specified size and optional trade options.", "helpUrl": "" } ]); /** * time_in_force * Sets the time in force for the order (GTC, FOK, IOC). */ Blockly.defineBlocksWithJsonArray([{ "type": "time_in_force", "message0": "Time in Force %1", "args0": [ { "type": "field_dropdown", "name": "tif", "options": [ ["GTC (Good Till Canceled)", "gtc"], ["FOK (Fill or Kill)", "fok"], ["IOC (Immediate or Cancel)", "ioc"] ] } ], "previousStatement": "trade_option", "nextStatement": "trade_option", "colour": 230, "tooltip": "Select time in force for the order.", "helpUrl": "" }]); /** * stop_loss * Sets the Stop Loss parameter for a trade. */ Blockly.defineBlocksWithJsonArray([ { "type": "stop_loss", "message0": "Stop Loss %1", "args0": [ { "type": "input_value", "name": "stop_loss_input", "check": ["number", "dynamic_value"] // Accepts numerical value or dynamic value } ], "previousStatement": "trade_option", "nextStatement": "trade_option", "colour": 230, "tooltip": "Set Stop Loss parameters.", "helpUrl": "" } ]); /** * take_profit * Sets the Take Profit parameter for a trade. */ Blockly.defineBlocksWithJsonArray([ { "type": "take_profit", "message0": "Take Profit %1", "args0": [ { "type": "input_value", "name": "take_profit_input", "check": ["number", "dynamic_value"] // Accepts numerical value or dynamic value } ], "previousStatement": "trade_option", "nextStatement": "trade_option", "colour": 230, "tooltip": "Set Take Profit parameters.", "helpUrl": "" } ]); /** * limit * Sets the Price parameter for a trade order. * Accepts numerical value or dynamic value if a single value is provided * the limit order will buy/sell at market price if the price reaches the * provided value. If two values are provided a limit order will be set for the * second value if the price reaches the first value. */ Blockly.defineBlocksWithJsonArray([ { "type": "limit", "message0": "Limit %1", "args0": [ { "type": "input_value", "name": "limit_input", "check": ["number", "dynamic_value"] } ], "previousStatement": "trade_option", "nextStatement": "trade_option", "colour": 230, "tooltip": "Set Limit parameters.", "helpUrl": "" } ]); /** * target_market * Defines the target market for executing trades with specified Time Frame, Exchange, and Symbol. */ Blockly.defineBlocksWithJsonArray([{ "type": "target_market", "message0": "Target market: TF %1 Ex %2 Sym %3", "args0": [ { "type": "field_dropdown", "name": "TF", "options": timeframeOptions }, { "type": "field_dropdown", "name": "EXC", "options": exchangeOptions }, { "type": "field_dropdown", "name": "SYM", "options": symbolOptions } ], "previousStatement": "trade_option", // Allows chaining with other trade options "nextStatement": "trade_option", "colour": 230, "tooltip": "Choose the target market for executing trades.", "helpUrl": "" }]); /************************************************ * CONTROL BLOCKS * ************************************************/ /** * Overrides all and pauses the strategy. * No new orders will be placed while true. */ Blockly.defineBlocksWithJsonArray([{ "type": "strategy_pause", "message0": "If %1 halt strategy", "args0": [ { "type": "field_dropdown", "name": "flag_value", "options": [["True", "True"], ["False", "False"]] } ], "previousStatement": null, "nextStatement": null, "colour": 230, "tooltip": "Set the flag to True to stop placing orders.", "helpUrl": "" }]); /** * Overrides all and pauses the strategy and exits trades. * No new orders will be placed. The strategies open trades * will be closed depending on the configuration. */ Blockly.defineBlocksWithJsonArray([{ "type": "strategy_exit", "message0": "If %1 exit strategy close %2 trades", "args0": [ { "type": "field_dropdown", "name": "flag_value", "options": [["True", "True"], ["False", "False"]] }, { "type": "field_dropdown", "name": "option_value", "options": [["all", "all"], ["in_profit", "in_profit"], ["in_loss", "in_loss"]] } ], "previousStatement": null, "nextStatement": null, "colour": 230, "tooltip": "Set the flag to True to stop placing orders.", "helpUrl": "" }]); /*************************************************** * INFO (FLAGS, VARIABLE, AND NOTIFICATION BLOCKS) * ***************************************************/ /** * notify_user * Sends a notification message to the user. */ Blockly.defineBlocksWithJsonArray([{ "type": "notify_user", "message0": "Notify User with Message %1", "args0": [ { "type": "field_input", "name": "MESSAGE", "text": "Your message here" } ], "previousStatement": null, "nextStatement": null, "colour": 120, "tooltip": "Sends a notification message to the user.", "helpUrl": "" }]); /** * get_variable * Retrieves the value of a specified variable. */ Blockly.defineBlocksWithJsonArray([{ "type": "get_variable", "message0": "Get variable %1 %2", "args0": [ { "type": "field_input", "name": "variable_name", "text": "my_var" }, { "type": "input_value", "name": "NEXT", "check": "dynamic_value" } ], "output": "dynamic_value", "colour": 330, "tooltip": "Get the value of a variable.", "helpUrl": "" }]); /** * set_variable * Sets a specified variable to a given value. */ Blockly.defineBlocksWithJsonArray([{ "type": "set_variable", "message0": "Set variable %1 to %2", "args0": [ { "type": "field_input", "name": "variable_name", "text": "my_var" }, { "type": "input_value", "name": "value", "check": ["number", "dynamic_value"] // Accepts numerical value or dynamic value } ], "previousStatement": null, "nextStatement": null, "colour": 330, "tooltip": "Set a variable to a value.", "helpUrl": "" }]); /** * flag_is_set * Checks if a specified flag is set to True. */ Blockly.defineBlocksWithJsonArray([{ "type": "flag_is_set", "message0": "flag %1 is set", "args0": [ { "type": "field_input", "name": "flag_name", "text": "flag_name" } ], "output": "Boolean", "colour": 160, "tooltip": "Check if the specified flag is set to True.", "helpUrl": "" }]); /** * set_flag * Sets a specified flag to True or False based on a Boolean condition. */ Blockly.defineBlocksWithJsonArray([{ "type": "set_flag", "message0": "If %1 then set flag %2 to %3", "args0": [ { "type": "input_value", // Boolean condition "name": "condition", "check": "Boolean" }, { "type": "field_input", "name": "flag_name", "text": "flag_name" }, { "type": "field_dropdown", "name": "flag_value", "options": [["True", "True"], ["False", "False"]] } ], "previousStatement": null, "nextStatement": null, "colour": 230, "tooltip": "Set a flag to True or False if the condition is met.", "helpUrl": "" }]); // Final log to confirm block definitions console.log('Custom blocks defined with dynamic_value support and proper categorization'); }