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);
}