diff --git a/archived_code/test_DataCache.py b/archived_code/test_DataCache.py index 26c6333..102efb3 100644 --- a/archived_code/test_DataCache.py +++ b/archived_code/test_DataCache.py @@ -5,218 +5,57 @@ "type": "strategy", "statements": [ { - "type": "execute_if", + "type": "set_available_strategy_balance", "inputs": { - "CONDITION": { - "type": "comparison", - "operator": "<", + "BALANCE": { + "type": "math_operation", "inputs": { - "LEFT": { - "type": "risk_ratio", - "inputs": {} - }, - "RIGHT": { - "type": "dynamic_value", - "values": [ - { - "type": "current_balance", - "inputs": {} - } - ] - } - } - } - }, - "statements": { - "DO": [ - { - "type": "max_position_size", - "inputs": { - "MAX_SIZE": { - "type": "available_balance", - "inputs": {} - } - }, - "next": { - "type": "execute_if", + "operator": "add", + "left_operand": 1, + "right_operand": { + "type": "math_operation", "inputs": { - "CONDITION": { - "type": "is_false", + "operator": "add", + "left_operand": { + "type": "power", "inputs": { - "condition": { - "type": "order_status", - "inputs": { - "order_name": "order_name", - "status": "filled" - } - } + "base": 2, + "exponent": 3 } - } - }, - "statements": { - "DO": [ - { - "type": "execute_if", - "inputs": { - "CONDITION": { - "type": "comparison", - "operator": ">", - "inputs": { - "LEFT": { - "type": "dynamic_value", - "values": [ - { - "type": "last_candle_value", - "inputs": { - "source": {}, - "candle_part": "open" - } - } - ] - }, - "RIGHT": { - "type": "dynamic_value", - "values": [ - 44 - ] - } - } - } - }, - "statements": { - "DO": [ - { - "type": "trade_action", - "trade_type": "buy", - "inputs": { - "size": { - "type": "math_operation", - "inputs": { - "operator": "divide", - "left_operand": { - "type": "starting_balance", - "inputs": {} - }, - "right_operand": 15 - } - } - }, - "trade_options": [ - { - "type": "name_order", - "inputs": { - "order_name": "order_name" - } - }, - { - "type": "target_market", - "inputs": { - "time_frame": "15m", - "exchange": "binance", - "symbol": "ETH/BTC" - } - } - ] - } - ] - } - } - ] - } - } - }, - { - "type": "execute_if", - "inputs": { - "CONDITION": { - "type": "is_false", - "inputs": { - "condition": { - "type": "order_status", - "inputs": { - "order_name": "order_name", - "status": "filled" - } - } - } - } - }, - "statements": { - "DO": [ - { - "type": "execute_if", + }, + "right_operand": { + "type": "math_operation", "inputs": { - "CONDITION": { - "type": "comparison", - "operator": ">", + "operator": "multiply", + "left_operand": { + "type": "min", "inputs": { - "LEFT": { - "type": "dynamic_value", - "values": [ - { - "type": "last_candle_value", - "inputs": { - "source": {}, - "candle_part": "open" - } - } - ] - }, - "RIGHT": { - "type": "dynamic_value", - "values": [ - 44 - ] - } - } - } - }, - "statements": { - "DO": [ - { - "type": "trade_action", - "trade_type": "buy", - "inputs": { - "size": { - "type": "math_operation", - "inputs": { - "operator": "divide", - "left_operand": { - "type": "starting_balance", - "inputs": {} - }, - "right_operand": 15 - } - } - }, - "trade_options": [ + "numbers": [ { - "type": "name_order", - "inputs": { - "order_name": "order_name" - } + "type": "current_balance", + "inputs": {} }, { - "type": "target_market", - "inputs": { - "time_frame": "15m", - "exchange": "binance", - "symbol": "ETH/BTC" - } + "type": "dynamic_value", + "values": [ + 5, + 6 + ] } ] } - ] + }, + "right_operand": 4 } } - ] + } } } - ] + } } } ] }, - "workspace": "Execute the enclosed statements if the condition is true.<Compare two values using operators like >, <, ==.Calculate and retrieve the current risk ratio.Retrieve the current balance of the strategy.Set a maximum limit on the number of positions the strategy can hold.Retrieve the overall available (liquid) balance of the user.Execute the enclosed statements if the condition is true.Check if a condition is false.order_namepartialGet the status of a named order.Execute the enclosed statements if the condition is true.>Compare two values using operators like >, <, ==.openRetrieve a specific part (Open, High, Low, Close) of the last candle from a given source.44Enter a numerical value. Chain multiple for a list.buyExecute a Buy/Sell trade based on a condition with specified size and options.DIVIDEPerform basic arithmetic operations between two values.Retrieve the starting balance of the strategy.15Enter a numerical value. Chain multiple for a list.order_nameAssign a custom name to the current order.15mbinanceETH/BTCChoose the target market for posting orders." + "workspace": "Set the balance allocated to the strategy.ADDPerform basic arithmetic operations between two values.1Enter a numerical value. Chain multiple for a list.ADDPerform basic arithmetic operations between two values.Raise a number to the power of another number (x^y).2Enter a numerical value. Chain multiple for a list.3Enter a numerical value. Chain multiple for a list.MULTIPLYPerform basic arithmetic operations between two values.Determine the minimum value among given numbers.Retrieve the current balance of the strategy.5Enter a numerical value. Chain multiple for a list.6Enter a numerical value. Chain multiple for a list.4Enter a numerical value. Chain multiple for a list." } """ \ No newline at end of file diff --git a/src/BrighterTrades.py b/src/BrighterTrades.py index 25c8bec..5153657 100644 --- a/src/BrighterTrades.py +++ b/src/BrighterTrades.py @@ -345,11 +345,10 @@ class BrighterTrades: return {"success": False, "message": "Invalid or empty strategy name"} if not isinstance(data['workspace'], str) or not data['workspace'].strip(): return {"success": False, "message": "Invalid or empty workspace data"} - if not isinstance(data['code'], list) or not data['code']: + if not isinstance(data['code'], dict) or not data['code']: return {"success": False, "message": "Invalid or empty strategy code"} # Serialize code to JSON string for storage - import json code_json = json.dumps(data['code']) # Prepare the strategy data for insertion diff --git a/src/Strategies.py b/src/Strategies.py index 273b1db..a680ac0 100644 --- a/src/Strategies.py +++ b/src/Strategies.py @@ -744,7 +744,15 @@ class Strategies: if not node_type: continue # Skip nodes without a type - if node_type == 'trade_action': + if node_type == 'strategy': + # Process the 'strategy' node + statements = node.get('statements', []) + if statements: + code_lines.extend(self.generate_code_from_json(statements, default_source, indent_level)) + elif node_type == 'execute_if': + # Handle 'execute_if' node + code_lines.extend(self.handle_execute_if(node, default_source, indent_level)) + elif node_type == 'trade_action': code_lines.extend(self.handle_trade_action(node, default_source, indent_level)) elif node_type == 'set_flag': code_lines.extend(self.handle_set_flag(node, indent_level)) @@ -783,6 +791,9 @@ class Strategies: :param condition_node: The condition node. :return: A string representing the condition. """ + if not isinstance(condition_node, dict): + # If condition_node is not a dict, return its string representation + return str(condition_node) node_type = condition_node.get('type') if not node_type: return 'False' # Default to False if node type is missing @@ -790,8 +801,9 @@ class Strategies: # Handling different condition types if node_type == 'comparison': operator = condition_node.get('operator') - left_node = condition_node.get('left_operand') # Ensure consistent key - right_node = condition_node.get('right_operand') + inputs = condition_node.get('inputs', {}) + left_node = inputs.get('LEFT') + right_node = inputs.get('RIGHT') left_expr = self.generate_condition_code(left_node) right_expr = self.generate_condition_code(right_node) operator_map = { @@ -805,6 +817,19 @@ class Strategies: python_operator = operator_map.get(operator, operator) return f"({left_expr} {python_operator} {right_expr})" + elif node_type == 'dynamic_value': + values = condition_node.get('values', []) + if len(values) == 1: + value = values[0] + if isinstance(value, dict): + return self.generate_condition_code(value) + else: + # If value is not a dict, return its string representation + return str(value) + else: + # Handle lists of values if necessary + return '0' + elif node_type == 'logical_and': conditions = condition_node.get('conditions', []) condition_exprs = [self.generate_condition_code(cond) for cond in conditions] @@ -1084,8 +1109,11 @@ class Strategies: # Return the inputted value. elif node_type == 'value_input': - value = condition_node.get('value', 0) - return str(value) + values = condition_node.get('values', []) + if len(values) == 1: + return str(values[0]) + else: + return '0' # Return a number elif node_type == 'number': @@ -1101,6 +1129,23 @@ class Strategies: logger.warning(f"Unhandled condition node type: {node_type}") return 'False' # Default to False for unhandled types + def handle_execute_if(self, node: dict, default_source: dict, indent_level: int) -> list[str]: + code_lines = [] + indent = ' ' * indent_level + + condition_node = node.get('inputs', {}).get('CONDITION') + if not condition_node: + logger.error("Condition missing in 'execute_if' node.") + return code_lines + + condition_code = self.generate_condition_code(condition_node) + code_lines.append(f"{indent}if {condition_code}:") + # Process the 'DO' statements under this condition + do_statements = node.get('statements', {}).get('DO', []) + code_lines.extend(self.generate_code_from_json(do_statements, default_source, indent_level + 1)) + + return code_lines + def handle_strategy_pause(self, node: dict, indent_level: int) -> list[str]: """ Handles the 'strategy_pause' node type. @@ -1146,8 +1191,16 @@ class Strategies: nested_actions = node.get('statements', {}).get('DO', []) resume_conditions.extend(self.extract_resume_conditions(nested_actions)) elif 'statements' in node: - resume_conditions.extend(self.extract_resume_conditions(node['statements'].get('DO', []))) - + statements = node['statements'] + if isinstance(statements, dict): + do_statements = statements.get('DO', []) + resume_conditions.extend(self.extract_resume_conditions(do_statements)) + elif isinstance(statements, list): + for sub_node in statements: + resume_conditions.extend(self.extract_resume_conditions(sub_node)) + else: + # Handle other possible types if necessary + pass return resume_conditions def handle_strategy_exit(self, node: dict, indent_level: int) -> list[str]: diff --git a/src/static/Strategies.js b/src/static/Strategies.js index c434e48..6544690 100644 --- a/src/static/Strategies.js +++ b/src/static/Strategies.js @@ -69,6 +69,11 @@ class StratUIManager { try { await this.workspaceManager.initWorkspace(); console.log("Blockly workspace initialized."); + // Restore workspace from XML if editing + if (action === 'edit' && strategyData && strategyData.workspace) { + this.workspaceManager.loadWorkspaceFromXml(strategyData.workspace); + console.log("Workspace restored from XML."); + } } catch (error) { console.error("Failed to initialize Blockly workspace:", error); }