Strtegies submit an are editable.

This commit is contained in:
Rob 2024-11-05 12:02:50 -04:00
parent 50bcfa05cd
commit 9d830fe8fa
4 changed files with 97 additions and 201 deletions

View File

@ -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": {}
"operator": "add",
"left_operand": 1,
"right_operand": {
"type": "math_operation",
"inputs": {
"operator": "add",
"left_operand": {
"type": "power",
"inputs": {
"base": 2,
"exponent": 3
}
},
"RIGHT": {
"type": "dynamic_value",
"values": [
"right_operand": {
"type": "math_operation",
"inputs": {
"operator": "multiply",
"left_operand": {
"type": "min",
"inputs": {
"numbers": [
{
"type": "current_balance",
"inputs": {}
}
]
}
}
}
},
"statements": {
"DO": [
{
"type": "max_position_size",
"inputs": {
"MAX_SIZE": {
"type": "available_balance",
"inputs": {}
}
},
"next": {
"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",
"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"
}
}
5,
6
]
}
]
}
}
]
}
}
},
{
"type": "execute_if",
"inputs": {
"CONDITION": {
"type": "is_false",
"inputs": {
"condition": {
"type": "order_status",
"inputs": {
"order_name": "order_name",
"status": "filled"
"right_operand": 4
}
}
}
}
}
}
},
"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"
}
}
]
}
]
}
}
]
}
}
]
}
}
]
},
"workspace": "<xml xmlns=\"https://developers.google.com/blockly/xml\"><block type=\"execute_if\" id=\"MsS{sEm446Tq-9cZ?LEM\" x=\"50\" y=\"110\"><comment pinned=\"false\" h=\"80\" w=\"160\">Execute the enclosed statements if the condition is true.</comment><value name=\"CONDITION\"><block type=\"comparison\" id=\"o$er@YT|44pRfD2*;kC%\"><field name=\"OPERATOR\">&lt;</field><comment pinned=\"false\" h=\"80\" w=\"160\">Compare two values using operators like &gt;, &lt;, ==.</comment><value name=\"LEFT\"><block type=\"risk_ratio\" id=\"-{)}8vrsu.uQ`,}~MEf-\"><comment pinned=\"false\" h=\"80\" w=\"160\">Calculate and retrieve the current risk ratio.</comment></block></value><value name=\"RIGHT\"><block type=\"current_balance\" id=\"rG=}HE!*$H|BWca!-G+%\"><comment pinned=\"false\" h=\"80\" w=\"160\">Retrieve the current balance of the strategy.</comment></block></value></block></value><statement name=\"DO\"><block type=\"max_position_size\" id=\"p{Do;wN=r3%T.7QD!]H@\"><comment pinned=\"false\" h=\"80\" w=\"160\">Set a maximum limit on the number of positions the strategy can hold.</comment><value name=\"MAX_SIZE\"><block type=\"available_balance\" id=\"H;h(SZy-/g/;;|S_]YQb\"><comment pinned=\"false\" h=\"80\" w=\"160\">Retrieve the overall available (liquid) balance of the user.</comment></block></value><next><block type=\"execute_if\" id=\"85pyvJR)Fr*LmqgKnIUm\"><comment pinned=\"false\" h=\"80\" w=\"160\">Execute the enclosed statements if the condition is true.</comment><value name=\"CONDITION\"><block type=\"is_false\" id=\"(vRWbh:/a=bX}${W4(/t\"><comment pinned=\"false\" h=\"80\" w=\"160\">Check if a condition is false.</comment><value name=\"condition\"><block type=\"order_status\" id=\"v#j1BnPG5pKC$M?csI)8\"><field name=\"ORDER_NAME\">order_name</field><field name=\"order_status\">partial</field><comment pinned=\"false\" h=\"80\" w=\"160\">Get the status of a named order.</comment></block></value></block></value><statement name=\"DO\"><block type=\"execute_if\" id=\"+dPkaDvC^21ylWseCZV;\"><comment pinned=\"false\" h=\"80\" w=\"160\">Execute the enclosed statements if the condition is true.</comment><value name=\"CONDITION\"><block type=\"comparison\" id=\"YTu*wGkeOU0k4]D|(j*:\"><field name=\"OPERATOR\">&gt;</field><comment pinned=\"false\" h=\"80\" w=\"160\">Compare two values using operators like &gt;, &lt;, ==.</comment><value name=\"LEFT\"><block type=\"last_candle_value\" id=\"8h3nZn?#t3UXcuU}icCC\"><field name=\"candle_part\">open</field><comment pinned=\"false\" h=\"80\" w=\"160\">Retrieve a specific part (Open, High, Low, Close) of the last candle from a given source.</comment></block></value><value name=\"RIGHT\"><block type=\"value_input\" id=\"i|%1Z,IK5~WCR5t~[T=J\"><field name=\"VALUE\">44</field><comment pinned=\"false\" h=\"80\" w=\"160\">Enter a numerical value. Chain multiple for a list.</comment></block></value></block></value><statement name=\"DO\"><block type=\"trade_action\" id=\"CYMHOlTFGfsK|l:ce{bX\"><field name=\"tradeType\">buy</field><comment pinned=\"false\" h=\"80\" w=\"160\">Execute a Buy/Sell trade based on a condition with specified size and options.</comment><value name=\"size\"><block type=\"math_operation\" id=\"^+dd,6d[Yg#w+bS|C{{S\"><field name=\"operator\">DIVIDE</field><comment pinned=\"false\" h=\"80\" w=\"160\">Perform basic arithmetic operations between two values.</comment><value name=\"LEFT\"><block type=\"starting_balance\" id=\"Bi5*6JEj#xP`DK9M1-p^\"><comment pinned=\"false\" h=\"80\" w=\"160\">Retrieve the starting balance of the strategy.</comment></block></value><value name=\"RIGHT\"><block type=\"value_input\" id=\".kd4Xeke%72-6/tdATz(\"><field name=\"VALUE\">15</field><comment pinned=\"false\" h=\"80\" w=\"160\">Enter a numerical value. Chain multiple for a list.</comment></block></value></block></value><statement name=\"trade_options\"><block type=\"name_order\" id=\"c;$K`P/c1nf2Ut)yJf=]\"><field name=\"order_name\">order_name</field><comment pinned=\"false\" h=\"80\" w=\"160\">Assign a custom name to the current order.</comment><next><block type=\"target_market\" id=\"FsX9_==AQf?DKtj]1C`]\"><field name=\"TF\">15m</field><field name=\"EXC\">binance</field><field name=\"SYM\">ETH/BTC</field><comment pinned=\"false\" h=\"80\" w=\"160\">Choose the target market for posting orders.</comment></block></next></block></statement></block></statement></block></statement></block></next></block></statement></block></xml>"
"workspace": "<xml xmlns=\"https://developers.google.com/blockly/xml\"><block type=\"set_available_strategy_balance\" id=\"AC+~IeO;#NLcE`*p`-{8\" x=\"-250\" y=\"130\"><comment pinned=\"false\" h=\"80\" w=\"160\">Set the balance allocated to the strategy.</comment><value name=\"BALANCE\"><block type=\"math_operation\" id=\"|-W{hIFm.z5Bd#m-OZs}\"><field name=\"operator\">ADD</field><comment pinned=\"false\" h=\"80\" w=\"160\">Perform basic arithmetic operations between two values.</comment><value name=\"LEFT\"><block type=\"value_input\" id=\"3`4X?VL:]|2FbEiMRz]f\"><field name=\"VALUE\">1</field><comment pinned=\"false\" h=\"80\" w=\"160\">Enter a numerical value. Chain multiple for a list.</comment></block></value><value name=\"RIGHT\"><block type=\"math_operation\" id=\"%~{X-%0Q37cn0L2aul,8\"><field name=\"operator\">ADD</field><comment pinned=\"false\" h=\"80\" w=\"160\">Perform basic arithmetic operations between two values.</comment><value name=\"LEFT\"><block type=\"power\" id=\"3;*+0$b19;lFVk%5iR({\"><comment pinned=\"false\" h=\"80\" w=\"160\">Raise a number to the power of another number (x^y).</comment><value name=\"VALUES\"><block type=\"value_input\" id=\"z`L(+hvv*Fu#slvL`yDj\"><field name=\"VALUE\">2</field><comment pinned=\"false\" h=\"80\" w=\"160\">Enter a numerical value. Chain multiple for a list.</comment><value name=\"NEXT\"><block type=\"value_input\" id=\"r6%+3l|2TezFf/hj^5:o\"><field name=\"VALUE\">3</field><comment pinned=\"false\" h=\"80\" w=\"160\">Enter a numerical value. Chain multiple for a list.</comment></block></value></block></value></block></value><value name=\"RIGHT\"><block type=\"math_operation\" id=\"(O686k#xdA9_nW5]s4*;\"><field name=\"operator\">MULTIPLY</field><comment pinned=\"false\" h=\"80\" w=\"160\">Perform basic arithmetic operations between two values.</comment><value name=\"LEFT\"><block type=\"min\" id=\"{XPyvd;n_o~??i(P65Yi\"><comment pinned=\"false\" h=\"80\" w=\"160\">Determine the minimum value among given numbers.</comment><value name=\"VALUES\"><block type=\"current_balance\" id=\"BapPJm/W8_)QeI98~JF6\"><comment pinned=\"false\" h=\"80\" w=\"160\">Retrieve the current balance of the strategy.</comment><value name=\"VALUES\"><block type=\"value_input\" id=\"4:wZlOvQQJ}b)cO6MSh~\"><field name=\"VALUE\">5</field><comment pinned=\"false\" h=\"80\" w=\"160\">Enter a numerical value. Chain multiple for a list.</comment><value name=\"NEXT\"><block type=\"value_input\" id=\"L.Hk_E@2r6#_F)1UrrZG\"><field name=\"VALUE\">6</field><comment pinned=\"false\" h=\"80\" w=\"160\">Enter a numerical value. Chain multiple for a list.</comment></block></value></block></value></block></value></block></value><value name=\"RIGHT\"><block type=\"value_input\" id=\"xjq($pfgII*[?r|Mu:*F\"><field name=\"VALUE\">4</field><comment pinned=\"false\" h=\"80\" w=\"160\">Enter a numerical value. Chain multiple for a list.</comment></block></value></block></value></block></value></block></value></block></xml>"
}
"""

View File

@ -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

View File

@ -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]:

View File

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