Refactor code for improved readability and consistency
- Cleaned up whitespace and formatting in various files including http.py, language.py, logger.py, safe_exec.py, and SQL migration scripts. - Consolidated import statements and removed unnecessary blank lines. - Updated logging configuration for better clarity. - Enhanced the safe execution code with improved error handling and logging. - Removed commented-out code and unnecessary variables in backfill_zero_trades.py and other scripts. - Added a pyproject.toml for Ruff and Vulture configuration. - Introduced requirements-dev.txt for development dependencies. - Removed commented-out stock entries in init.sql for cleaner migration scripts.
This commit is contained in:
@@ -1,41 +1,41 @@
|
||||
import json
|
||||
from typing import Dict, Any, List
|
||||
from typing import Any, Dict
|
||||
|
||||
|
||||
class StrategyCompiler:
|
||||
def compile(self, config: Dict[str, Any]) -> str:
|
||||
"""
|
||||
Compiles the strategy configuration JSON into executable Python code.
|
||||
"""
|
||||
|
||||
|
||||
# Extract configurations
|
||||
name = config.get('name', 'Generated Strategy')
|
||||
entry_rules = config.get('entry_rules', [])
|
||||
position_config = config.get('position_config', {})
|
||||
pyramiding_rules = config.get('pyramiding_rules', {})
|
||||
risk_management = config.get('risk_management', {})
|
||||
|
||||
name = config.get("name", "Generated Strategy")
|
||||
entry_rules = config.get("entry_rules", [])
|
||||
position_config = config.get("position_config", {})
|
||||
pyramiding_rules = config.get("pyramiding_rules", {})
|
||||
risk_management = config.get("risk_management", {})
|
||||
|
||||
# 1. Imports and Setup
|
||||
code = self._get_header(name)
|
||||
|
||||
|
||||
# 2. Parameters (Variables)
|
||||
code += self._get_parameters(position_config, pyramiding_rules, risk_management)
|
||||
|
||||
|
||||
# 3. Indicators Calculation
|
||||
code += self._get_indicators_calculation(entry_rules)
|
||||
|
||||
|
||||
# 4. Signal Logic (Entry Conditions)
|
||||
code += self._get_entry_logic(entry_rules)
|
||||
|
||||
|
||||
# 5. Core Loop (Position Management) - Based on code2.py
|
||||
code += self._get_core_loop(position_config, pyramiding_rules, risk_management)
|
||||
|
||||
|
||||
# 6. Output Formatting
|
||||
code += self._get_output_section(name, entry_rules)
|
||||
|
||||
|
||||
return code
|
||||
|
||||
def _get_header(self, name):
|
||||
return f'''
|
||||
return f"""
|
||||
# Generated Strategy: {name}
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
@@ -44,28 +44,27 @@ import numpy as np
|
||||
def get_val(arr, i, default=0):
|
||||
if i < 0 or i >= len(arr): return default
|
||||
return arr[i]
|
||||
'''
|
||||
"""
|
||||
|
||||
def _get_parameters(self, pos_config, pyr_rules, risk_mgmt):
|
||||
# Default values
|
||||
initial_size = pos_config.get('initial_size_pct', 10) / 100.0
|
||||
leverage = pos_config.get('leverage', 1)
|
||||
max_pyramiding = pos_config.get('max_pyramiding', 0)
|
||||
|
||||
pyr_enabled = pyr_rules.get('enabled', False)
|
||||
add_size = pyr_rules.get('size_pct', 0) / 100.0 if pyr_enabled else 0
|
||||
add_threshold = pyr_rules.get('value', 0) / 100.0
|
||||
|
||||
stop_loss = risk_mgmt.get('stop_loss', {})
|
||||
sl_enabled = stop_loss.get('enabled', False)
|
||||
sl_pct = stop_loss.get('value', 0) / 100.0 if sl_enabled else 0.0
|
||||
|
||||
trailing = risk_mgmt.get('trailing_stop', {})
|
||||
ts_enabled = trailing.get('enabled', False)
|
||||
ts_activation = trailing.get('activation_profit', 0) / 100.0
|
||||
ts_callback = trailing.get('callback_pct', 0) / 100.0
|
||||
|
||||
return f'''
|
||||
initial_size = pos_config.get("initial_size_pct", 10) / 100.0
|
||||
leverage = pos_config.get("leverage", 1)
|
||||
max_pyramiding = pos_config.get("max_pyramiding", 0)
|
||||
|
||||
pyr_enabled = pyr_rules.get("enabled", False)
|
||||
add_size = pyr_rules.get("size_pct", 0) / 100.0 if pyr_enabled else 0
|
||||
add_threshold = pyr_rules.get("value", 0) / 100.0
|
||||
|
||||
stop_loss = risk_mgmt.get("stop_loss", {})
|
||||
sl_enabled = stop_loss.get("enabled", False)
|
||||
sl_pct = stop_loss.get("value", 0) / 100.0 if sl_enabled else 0.0
|
||||
|
||||
trailing = risk_mgmt.get("trailing_stop", {})
|
||||
ts_activation = trailing.get("activation_profit", 0) / 100.0
|
||||
ts_callback = trailing.get("callback_pct", 0) / 100.0
|
||||
|
||||
return f"""
|
||||
# ===========================
|
||||
# 1. Parameters
|
||||
# ===========================
|
||||
@@ -75,13 +74,13 @@ max_pyramiding = {max_pyramiding}
|
||||
|
||||
# Pyramiding
|
||||
add_position_pct = {add_size}
|
||||
add_threshold_pct = {add_threshold}
|
||||
add_threshold_pct = {add_threshold}
|
||||
|
||||
# Risk Management
|
||||
stop_loss_pct = {sl_pct}
|
||||
take_profit_activation = {ts_activation}
|
||||
trailing_callback = {ts_callback}
|
||||
'''
|
||||
"""
|
||||
|
||||
def _get_indicators_calculation(self, rules):
|
||||
code = """
|
||||
@@ -90,18 +89,18 @@ trailing_callback = {ts_callback}
|
||||
# ===========================
|
||||
"""
|
||||
calculated = set()
|
||||
|
||||
|
||||
for rule in rules:
|
||||
ind = rule.get('indicator')
|
||||
params = rule.get('params', {})
|
||||
|
||||
if ind == 'supertrend':
|
||||
ind = rule.get("indicator")
|
||||
params = rule.get("params", {})
|
||||
|
||||
if ind == "supertrend":
|
||||
key = f"st_{params.get('period')}_{params.get('multiplier')}"
|
||||
if key not in calculated:
|
||||
code += f"""
|
||||
# SuperTrend ({params.get('period')}, {params.get('multiplier')})
|
||||
period = {params.get('period', 14)}
|
||||
multiplier = {params.get('multiplier', 3.0)}
|
||||
# SuperTrend ({params.get("period")}, {params.get("multiplier")})
|
||||
period = {params.get("period", 14)}
|
||||
multiplier = {params.get("multiplier", 3.0)}
|
||||
df['hl2'] = (df['high'] + df['low']) / 2
|
||||
df['tr'] = np.maximum(df['high'] - df['low'], np.maximum(abs(df['high'] - df['close'].shift(1)), abs(df['low'] - df['close'].shift(1))))
|
||||
df['atr'] = df['tr'].ewm(alpha=1/period, adjust=False).mean()
|
||||
@@ -120,12 +119,12 @@ for i in range(1, len(df)):
|
||||
final_upper[i] = basic_upper[i]
|
||||
else:
|
||||
final_upper[i] = final_upper[i-1]
|
||||
|
||||
|
||||
if basic_lower[i] > final_lower[i-1] or close_arr[i-1] < final_lower[i-1]:
|
||||
final_lower[i] = basic_lower[i]
|
||||
else:
|
||||
final_lower[i] = final_lower[i-1]
|
||||
|
||||
|
||||
prev_trend = trend[i-1]
|
||||
if prev_trend == -1 and close_arr[i] > final_upper[i-1]:
|
||||
trend[i] = 1
|
||||
@@ -140,15 +139,15 @@ df['st_lower'] = final_lower
|
||||
"""
|
||||
calculated.add(key)
|
||||
|
||||
elif ind == 'ema':
|
||||
period = params.get('period', 20)
|
||||
elif ind == "ema":
|
||||
period = params.get("period", 20)
|
||||
key = f"ema_{period}"
|
||||
if key not in calculated:
|
||||
code += f"\ndf['ema_{period}'] = df['close'].ewm(span={period}, adjust=False).mean()\n"
|
||||
calculated.add(key)
|
||||
|
||||
elif ind == 'rsi':
|
||||
period = params.get('period', 14)
|
||||
elif ind == "rsi":
|
||||
period = params.get("period", 14)
|
||||
key = f"rsi_{period}"
|
||||
if key not in calculated:
|
||||
code += f"""
|
||||
@@ -161,10 +160,10 @@ df['rsi_{period}'] = 100 - (100 / (1 + rs))
|
||||
"""
|
||||
calculated.add(key)
|
||||
|
||||
elif ind == 'macd':
|
||||
fast = params.get('fast_period', 12)
|
||||
slow = params.get('slow_period', 26)
|
||||
signal = params.get('signal_period', 9)
|
||||
elif ind == "macd":
|
||||
fast = params.get("fast_period", 12)
|
||||
slow = params.get("slow_period", 26)
|
||||
signal = params.get("signal_period", 9)
|
||||
key = f"macd_{fast}_{slow}_{signal}"
|
||||
if key not in calculated:
|
||||
code += f"""
|
||||
@@ -177,9 +176,9 @@ df['macd_{fast}_{slow}_{signal}_hist'] = df['macd_{fast}_{slow}_{signal}_line']
|
||||
"""
|
||||
calculated.add(key)
|
||||
|
||||
elif ind == 'bollinger':
|
||||
period = params.get('period', 20)
|
||||
std_dev = params.get('std_dev', 2.0)
|
||||
elif ind == "bollinger":
|
||||
period = params.get("period", 20)
|
||||
std_dev = params.get("std_dev", 2.0)
|
||||
key = f"bb_{period}_{std_dev}"
|
||||
if key not in calculated:
|
||||
code += f"""
|
||||
@@ -192,9 +191,9 @@ df['bb_{period}_{std_dev}_mid'] = sma
|
||||
"""
|
||||
calculated.add(key)
|
||||
|
||||
elif ind == 'kdj':
|
||||
period = params.get('period', 9)
|
||||
signal_period = params.get('signal_period', 3)
|
||||
elif ind == "kdj":
|
||||
period = params.get("period", 9)
|
||||
signal_period = params.get("signal_period", 3)
|
||||
key = f"kdj_{period}_{signal_period}"
|
||||
if key not in calculated:
|
||||
code += f"""
|
||||
@@ -208,15 +207,15 @@ df['kdj_{period}_{signal_period}_j'] = 3 * df['kdj_{period}_{signal_period}_k']
|
||||
"""
|
||||
calculated.add(key)
|
||||
|
||||
elif ind == 'ma':
|
||||
period = params.get('period', 20)
|
||||
ma_type = params.get('ma_type', 'sma')
|
||||
elif ind == "ma":
|
||||
period = params.get("period", 20)
|
||||
ma_type = params.get("ma_type", "sma")
|
||||
key = f"ma_{ma_type}_{period}"
|
||||
if key not in calculated:
|
||||
if ma_type == 'ema':
|
||||
code += f"\ndf['ma_{ma_type}_{period}'] = df['close'].ewm(span={period}, adjust=False).mean()\n"
|
||||
if ma_type == "ema":
|
||||
code += f"\ndf['ma_{ma_type}_{period}'] = df['close'].ewm(span={period}, adjust=False).mean()\n"
|
||||
else:
|
||||
code += f"\ndf['ma_{ma_type}_{period}'] = df['close'].rolling(window={period}).mean()\n"
|
||||
code += f"\ndf['ma_{ma_type}_{period}'] = df['close'].rolling(window={period}).mean()\n"
|
||||
calculated.add(key)
|
||||
|
||||
return code
|
||||
@@ -232,139 +231,139 @@ df['raw_sell'] = False
|
||||
"""
|
||||
conditions_buy = []
|
||||
conditions_sell = []
|
||||
|
||||
|
||||
for rule in rules:
|
||||
ind = rule.get('indicator')
|
||||
params = rule.get('params', {})
|
||||
|
||||
if ind == 'supertrend':
|
||||
signal = rule.get('signal', 'trend_bullish')
|
||||
if signal == 'trend_bullish':
|
||||
ind = rule.get("indicator")
|
||||
params = rule.get("params", {})
|
||||
|
||||
if ind == "supertrend":
|
||||
signal = rule.get("signal", "trend_bullish")
|
||||
if signal == "trend_bullish":
|
||||
conditions_buy.append("(df['st_trend'] == 1) & (df['st_trend'].shift(1) == -1)")
|
||||
conditions_sell.append("(df['st_trend'] == -1) & (df['st_trend'].shift(1) == 1)")
|
||||
elif signal == 'is_uptrend':
|
||||
elif signal == "is_uptrend":
|
||||
conditions_buy.append("(df['st_trend'] == 1)")
|
||||
conditions_sell.append("(df['st_trend'] == -1)")
|
||||
|
||||
elif ind == 'ema':
|
||||
period = params.get('period', 20)
|
||||
operator = rule.get('operator', 'price_above')
|
||||
|
||||
elif ind == "ema":
|
||||
period = params.get("period", 20)
|
||||
operator = rule.get("operator", "price_above")
|
||||
col = f"df['ema_{period}']"
|
||||
if operator == 'price_above':
|
||||
if operator == "price_above":
|
||||
conditions_buy.append(f"(df['close'] > {col})")
|
||||
conditions_sell.append(f"(df['close'] < {col})")
|
||||
elif operator == 'price_below':
|
||||
elif operator == "price_below":
|
||||
conditions_buy.append(f"(df['close'] < {col})")
|
||||
conditions_sell.append(f"(df['close'] > {col})")
|
||||
elif operator == 'cross_up':
|
||||
elif operator == "cross_up":
|
||||
conditions_buy.append(f"(df['close'] > {col}) & (df['close'].shift(1) <= {col}.shift(1))")
|
||||
conditions_sell.append(f"(df['close'] < {col}) & (df['close'].shift(1) >= {col}.shift(1))")
|
||||
elif operator == 'cross_down':
|
||||
elif operator == "cross_down":
|
||||
conditions_buy.append(f"(df['close'] < {col}) & (df['close'].shift(1) >= {col}.shift(1))")
|
||||
conditions_sell.append(f"(df['close'] > {col}) & (df['close'].shift(1) <= {col}.shift(1))")
|
||||
|
||||
elif ind == 'rsi':
|
||||
period = params.get('period', 14)
|
||||
operator = rule.get('operator', '<')
|
||||
thresh = params.get('threshold', 30)
|
||||
elif ind == "rsi":
|
||||
period = params.get("period", 14)
|
||||
operator = rule.get("operator", "<")
|
||||
thresh = params.get("threshold", 30)
|
||||
col = f"df['rsi_{period}']"
|
||||
if operator == '<':
|
||||
if operator == "<":
|
||||
conditions_buy.append(f"({col} < {thresh})")
|
||||
conditions_sell.append(f"({col} > {100-thresh})")
|
||||
elif operator == '>':
|
||||
conditions_sell.append(f"({col} > {100 - thresh})")
|
||||
elif operator == ">":
|
||||
conditions_buy.append(f"({col} > {thresh})")
|
||||
conditions_sell.append(f"({col} < {100-thresh})")
|
||||
elif operator == 'cross_up':
|
||||
conditions_sell.append(f"({col} < {100 - thresh})")
|
||||
elif operator == "cross_up":
|
||||
conditions_buy.append(f"({col} > {thresh}) & ({col}.shift(1) <= {thresh})")
|
||||
conditions_sell.append(f"({col} < {100-thresh}) & ({col}.shift(1) >= {100-thresh})")
|
||||
elif operator == 'cross_down':
|
||||
conditions_sell.append(f"({col} < {100 - thresh}) & ({col}.shift(1) >= {100 - thresh})")
|
||||
elif operator == "cross_down":
|
||||
conditions_buy.append(f"({col} < {thresh}) & ({col}.shift(1) >= {thresh})")
|
||||
conditions_sell.append(f"({col} > {100-thresh}) & ({col}.shift(1) <= {100-thresh})")
|
||||
conditions_sell.append(f"({col} > {100 - thresh}) & ({col}.shift(1) <= {100 - thresh})")
|
||||
|
||||
elif ind == 'macd':
|
||||
fast = params.get('fast_period', 12)
|
||||
slow = params.get('slow_period', 26)
|
||||
signal = params.get('signal_period', 9)
|
||||
operator = rule.get('operator', 'diff_gt_dea')
|
||||
elif ind == "macd":
|
||||
fast = params.get("fast_period", 12)
|
||||
slow = params.get("slow_period", 26)
|
||||
signal = params.get("signal_period", 9)
|
||||
operator = rule.get("operator", "diff_gt_dea")
|
||||
line_col = f"df['macd_{fast}_{slow}_{signal}_line']"
|
||||
sig_col = f"df['macd_{fast}_{slow}_{signal}_signal']"
|
||||
|
||||
if operator == 'diff_gt_dea':
|
||||
|
||||
if operator == "diff_gt_dea":
|
||||
conditions_buy.append(f"({line_col} > {sig_col})")
|
||||
conditions_sell.append(f"({line_col} < {sig_col})")
|
||||
elif operator == 'diff_lt_dea':
|
||||
elif operator == "diff_lt_dea":
|
||||
conditions_buy.append(f"({line_col} < {sig_col})")
|
||||
conditions_sell.append(f"({line_col} > {sig_col})")
|
||||
elif operator == 'cross_up':
|
||||
elif operator == "cross_up":
|
||||
conditions_buy.append(f"({line_col} > {sig_col}) & ({line_col}.shift(1) <= {sig_col}.shift(1))")
|
||||
conditions_sell.append(f"({line_col} < {sig_col}) & ({line_col}.shift(1) >= {sig_col}.shift(1))")
|
||||
elif operator == 'cross_down':
|
||||
elif operator == "cross_down":
|
||||
conditions_buy.append(f"({line_col} < {sig_col}) & ({line_col}.shift(1) >= {sig_col}.shift(1))")
|
||||
conditions_sell.append(f"({line_col} > {sig_col}) & ({line_col}.shift(1) <= {sig_col}.shift(1))")
|
||||
|
||||
elif ind == 'bollinger':
|
||||
period = params.get('period', 20)
|
||||
std_dev = params.get('std_dev', 2.0)
|
||||
operator = rule.get('operator', 'price_above_upper')
|
||||
elif ind == "bollinger":
|
||||
period = params.get("period", 20)
|
||||
std_dev = params.get("std_dev", 2.0)
|
||||
operator = rule.get("operator", "price_above_upper")
|
||||
upper = f"df['bb_{period}_{std_dev}_upper']"
|
||||
lower = f"df['bb_{period}_{std_dev}_lower']"
|
||||
mid = f"df['bb_{period}_{std_dev}_mid']"
|
||||
|
||||
if operator == 'price_above_upper':
|
||||
|
||||
if operator == "price_above_upper":
|
||||
conditions_buy.append(f"(df['close'] > {upper})")
|
||||
conditions_sell.append(f"(df['close'] < {lower})")
|
||||
elif operator == 'price_below_lower':
|
||||
elif operator == "price_below_lower":
|
||||
conditions_buy.append(f"(df['close'] < {lower})")
|
||||
conditions_sell.append(f"(df['close'] > {upper})")
|
||||
elif operator == 'price_above_mid':
|
||||
elif operator == "price_above_mid":
|
||||
conditions_buy.append(f"(df['close'] > {mid})")
|
||||
conditions_sell.append(f"(df['close'] < {mid})")
|
||||
elif operator == 'price_below_mid':
|
||||
elif operator == "price_below_mid":
|
||||
conditions_buy.append(f"(df['close'] < {mid})")
|
||||
conditions_sell.append(f"(df['close'] > {mid})")
|
||||
elif operator == 'cross_up_lower':
|
||||
elif operator == "cross_up_lower":
|
||||
conditions_buy.append(f"(df['close'] > {lower}) & (df['close'].shift(1) <= {lower}.shift(1))")
|
||||
conditions_sell.append(f"(df['close'] < {upper}) & (df['close'].shift(1) >= {upper}.shift(1))")
|
||||
elif operator == 'cross_down_upper':
|
||||
elif operator == "cross_down_upper":
|
||||
conditions_buy.append(f"(df['close'] < {upper}) & (df['close'].shift(1) >= {upper}.shift(1))")
|
||||
conditions_sell.append(f"(df['close'] > {lower}) & (df['close'].shift(1) <= {lower}.shift(1))")
|
||||
|
||||
elif ind == 'kdj':
|
||||
period = params.get('period', 9)
|
||||
signal_period = params.get('signal_period', 3)
|
||||
operator = rule.get('operator', 'k_gt_d')
|
||||
elif ind == "kdj":
|
||||
period = params.get("period", 9)
|
||||
signal_period = params.get("signal_period", 3)
|
||||
operator = rule.get("operator", "k_gt_d")
|
||||
k_col = f"df['kdj_{period}_{signal_period}_k']"
|
||||
d_col = f"df['kdj_{period}_{signal_period}_d']"
|
||||
|
||||
if operator == 'k_gt_d':
|
||||
|
||||
if operator == "k_gt_d":
|
||||
conditions_buy.append(f"({k_col} > {d_col})")
|
||||
conditions_sell.append(f"({k_col} < {d_col})")
|
||||
elif operator == 'k_lt_d':
|
||||
elif operator == "k_lt_d":
|
||||
conditions_buy.append(f"({k_col} < {d_col})")
|
||||
conditions_sell.append(f"({k_col} > {d_col})")
|
||||
elif operator == 'gold_cross':
|
||||
elif operator == "gold_cross":
|
||||
conditions_buy.append(f"({k_col} > {d_col}) & ({k_col}.shift(1) <= {d_col}.shift(1))")
|
||||
conditions_sell.append(f"({k_col} < {d_col}) & ({k_col}.shift(1) >= {d_col}.shift(1))")
|
||||
elif operator == 'death_cross':
|
||||
elif operator == "death_cross":
|
||||
conditions_buy.append(f"({k_col} < {d_col}) & ({k_col}.shift(1) >= {d_col}.shift(1))")
|
||||
conditions_sell.append(f"({k_col} > {d_col}) & ({k_col}.shift(1) <= {d_col}.shift(1))")
|
||||
|
||||
elif ind == 'ma':
|
||||
period = params.get('period', 20)
|
||||
ma_type = params.get('ma_type', 'sma')
|
||||
operator = rule.get('operator', 'price_above')
|
||||
elif ind == "ma":
|
||||
period = params.get("period", 20)
|
||||
ma_type = params.get("ma_type", "sma")
|
||||
operator = rule.get("operator", "price_above")
|
||||
col = f"df['ma_{ma_type}_{period}']"
|
||||
|
||||
if operator == 'price_above':
|
||||
|
||||
if operator == "price_above":
|
||||
conditions_buy.append(f"(df['close'] > {col})")
|
||||
conditions_sell.append(f"(df['close'] < {col})")
|
||||
elif operator == 'price_below':
|
||||
elif operator == "price_below":
|
||||
conditions_buy.append(f"(df['close'] < {col})")
|
||||
conditions_sell.append(f"(df['close'] > {col})")
|
||||
elif operator == 'cross_up':
|
||||
elif operator == "cross_up":
|
||||
conditions_buy.append(f"(df['close'] > {col}) & (df['close'].shift(1) <= {col}.shift(1))")
|
||||
conditions_sell.append(f"(df['close'] < {col}) & (df['close'].shift(1) >= {col}.shift(1))")
|
||||
elif operator == 'cross_down':
|
||||
elif operator == "cross_down":
|
||||
conditions_buy.append(f"(df['close'] < {col}) & (df['close'].shift(1) >= {col}.shift(1))")
|
||||
conditions_sell.append(f"(df['close'] > {col}) & (df['close'].shift(1) <= {col}.shift(1))")
|
||||
|
||||
@@ -372,7 +371,7 @@ df['raw_sell'] = False
|
||||
code += f"\ndf['raw_buy'] = {' & '.join(conditions_buy)}\n"
|
||||
if conditions_sell:
|
||||
code += f"\ndf['raw_sell'] = {' & '.join(conditions_sell)}\n"
|
||||
|
||||
|
||||
return code
|
||||
|
||||
def _get_core_loop(self, pos_config, pyr_rules, risk_mgmt):
|
||||
@@ -418,15 +417,15 @@ for i in range(len(df)):
|
||||
current_close = close_arr[i]
|
||||
current_high = high_arr[i]
|
||||
current_low = low_arr[i]
|
||||
|
||||
|
||||
if position == 1:
|
||||
# Long Position
|
||||
if current_high > highest_price:
|
||||
highest_price = current_high
|
||||
|
||||
|
||||
profit_pct = (highest_price - avg_entry_price) / avg_entry_price
|
||||
current_profit_pct = (current_close - avg_entry_price) / avg_entry_price
|
||||
|
||||
|
||||
# 1. Trailing Stop
|
||||
if take_profit_activation > 0 and profit_pct >= take_profit_activation:
|
||||
drawdown = (highest_price - current_close) / avg_entry_price
|
||||
@@ -437,7 +436,7 @@ for i in range(len(df)):
|
||||
position = 0
|
||||
position_count = 0
|
||||
continue
|
||||
|
||||
|
||||
# 2. Stop Loss
|
||||
if stop_loss_pct > 0:
|
||||
loss_pct = (avg_entry_price - current_low) / avg_entry_price
|
||||
@@ -448,7 +447,7 @@ for i in range(len(df)):
|
||||
position = 0
|
||||
position_count = 0
|
||||
continue
|
||||
|
||||
|
||||
# 3. Signal Exit (if enabled)
|
||||
# Note: Code2 uses raw_sell_arr for exit
|
||||
if raw_sell_arr[i]:
|
||||
@@ -457,11 +456,11 @@ for i in range(len(df)):
|
||||
close_long_text[i] = "Signal Exit"
|
||||
position = 0
|
||||
position_count = 0
|
||||
|
||||
|
||||
# Reverse to Short if trade_direction allows (simplified here)
|
||||
# For now we just close.
|
||||
continue
|
||||
|
||||
|
||||
# 4. Pyramiding (Add Long)
|
||||
if max_pyramiding > 0 and position_count < max_pyramiding + 1 and current_profit_pct > 0:
|
||||
# Condition: Price rise by threshold
|
||||
@@ -473,18 +472,18 @@ for i in range(len(df)):
|
||||
add_long_text[i] = "Add Long"
|
||||
position_count += 1
|
||||
last_add_price = target_price
|
||||
|
||||
|
||||
elif position == -1:
|
||||
# Short Position
|
||||
# For Short, highest_price tracks the LOWEST price (best profit scenario)
|
||||
if highest_price == 0: highest_price = avg_entry_price
|
||||
if current_low < highest_price:
|
||||
highest_price = current_low
|
||||
|
||||
|
||||
# Profit: (Entry - Lowest) / Entry
|
||||
profit_pct = (avg_entry_price - highest_price) / avg_entry_price
|
||||
current_profit_pct = (avg_entry_price - current_close) / avg_entry_price
|
||||
|
||||
|
||||
# 1. Trailing Stop
|
||||
if take_profit_activation > 0 and profit_pct >= take_profit_activation:
|
||||
# Drawdown: (Current - Lowest) / Entry
|
||||
@@ -541,7 +540,7 @@ for i in range(len(df)):
|
||||
avg_entry_price = current_close
|
||||
last_add_price = current_close
|
||||
highest_price = current_close
|
||||
|
||||
|
||||
elif raw_sell_arr[i]:
|
||||
open_short_signals[i] = True
|
||||
open_short_price[i] = current_close
|
||||
@@ -568,64 +567,136 @@ df['close_long_text'] = close_long_text
|
||||
# Generate plot configs based on indicators
|
||||
plots = []
|
||||
for rule in rules:
|
||||
ind = rule.get('indicator')
|
||||
params = rule.get('params', {})
|
||||
if ind == 'supertrend':
|
||||
plots.append({
|
||||
"name": "SuperTrend Up", "type": "line", "data": "df['st_lower'].tolist()", "color": "#00FF00", "overlay": True
|
||||
})
|
||||
plots.append({
|
||||
"name": "SuperTrend Down", "type": "line", "data": "df['st_upper'].tolist()", "color": "#FF0000", "overlay": True
|
||||
})
|
||||
elif ind == 'ema':
|
||||
p = params.get('period', 20)
|
||||
plots.append({
|
||||
"name": f"EMA {p}", "type": "line", "data": f"df['ema_{p}'].tolist()", "color": "#FFA500", "overlay": True
|
||||
})
|
||||
elif ind == 'ma':
|
||||
p = params.get('period', 20)
|
||||
t = params.get('ma_type', 'sma')
|
||||
plots.append({
|
||||
"name": f"{t.upper()} {p}", "type": "line", "data": f"df['ma_{t}_{p}'].tolist()", "color": "#FFA500", "overlay": True
|
||||
})
|
||||
elif ind == 'bollinger':
|
||||
p = params.get('period', 20)
|
||||
d = params.get('std_dev', 2.0)
|
||||
plots.append({
|
||||
"name": "BB Upper", "type": "line", "data": f"df['bb_{p}_{d}_upper'].tolist()", "color": "#0088FE", "overlay": True
|
||||
})
|
||||
plots.append({
|
||||
"name": "BB Lower", "type": "line", "data": f"df['bb_{p}_{d}_lower'].tolist()", "color": "#0088FE", "overlay": True
|
||||
})
|
||||
ind = rule.get("indicator")
|
||||
params = rule.get("params", {})
|
||||
if ind == "supertrend":
|
||||
plots.append(
|
||||
{
|
||||
"name": "SuperTrend Up",
|
||||
"type": "line",
|
||||
"data": "df['st_lower'].tolist()",
|
||||
"color": "#00FF00",
|
||||
"overlay": True,
|
||||
}
|
||||
)
|
||||
plots.append(
|
||||
{
|
||||
"name": "SuperTrend Down",
|
||||
"type": "line",
|
||||
"data": "df['st_upper'].tolist()",
|
||||
"color": "#FF0000",
|
||||
"overlay": True,
|
||||
}
|
||||
)
|
||||
elif ind == "ema":
|
||||
p = params.get("period", 20)
|
||||
plots.append(
|
||||
{
|
||||
"name": f"EMA {p}",
|
||||
"type": "line",
|
||||
"data": f"df['ema_{p}'].tolist()",
|
||||
"color": "#FFA500",
|
||||
"overlay": True,
|
||||
}
|
||||
)
|
||||
elif ind == "ma":
|
||||
p = params.get("period", 20)
|
||||
t = params.get("ma_type", "sma")
|
||||
plots.append(
|
||||
{
|
||||
"name": f"{t.upper()} {p}",
|
||||
"type": "line",
|
||||
"data": f"df['ma_{t}_{p}'].tolist()",
|
||||
"color": "#FFA500",
|
||||
"overlay": True,
|
||||
}
|
||||
)
|
||||
elif ind == "bollinger":
|
||||
p = params.get("period", 20)
|
||||
d = params.get("std_dev", 2.0)
|
||||
plots.append(
|
||||
{
|
||||
"name": "BB Upper",
|
||||
"type": "line",
|
||||
"data": f"df['bb_{p}_{d}_upper'].tolist()",
|
||||
"color": "#0088FE",
|
||||
"overlay": True,
|
||||
}
|
||||
)
|
||||
plots.append(
|
||||
{
|
||||
"name": "BB Lower",
|
||||
"type": "line",
|
||||
"data": f"df['bb_{p}_{d}_lower'].tolist()",
|
||||
"color": "#0088FE",
|
||||
"overlay": True,
|
||||
}
|
||||
)
|
||||
# MACD, RSI, KDJ are typically separate panes, not overlay. The `overlay` param controls this.
|
||||
elif ind == 'macd':
|
||||
f = params.get('fast_period', 12)
|
||||
s = params.get('slow_period', 26)
|
||||
si = params.get('signal_period', 9)
|
||||
plots.append({
|
||||
"name": "MACD", "type": "line", "data": f"df['macd_{f}_{s}_{si}_line'].tolist()", "color": "#0088FE", "overlay": False
|
||||
})
|
||||
plots.append({
|
||||
"name": "Signal", "type": "line", "data": f"df['macd_{f}_{s}_{si}_signal'].tolist()", "color": "#FF8042", "overlay": False
|
||||
})
|
||||
elif ind == 'rsi':
|
||||
p = params.get('period', 14)
|
||||
plots.append({
|
||||
"name": f"RSI {p}", "type": "line", "data": f"df['rsi_{p}'].tolist()", "color": "#8884d8", "overlay": False
|
||||
})
|
||||
elif ind == 'kdj':
|
||||
p = params.get('period', 9)
|
||||
si = params.get('signal_period', 3)
|
||||
plots.append({
|
||||
"name": "K", "type": "line", "data": f"df['kdj_{p}_{si}_k'].tolist()", "color": "#8884d8", "overlay": False
|
||||
})
|
||||
plots.append({
|
||||
"name": "D", "type": "line", "data": f"df['kdj_{p}_{si}_d'].tolist()", "color": "#82ca9d", "overlay": False
|
||||
})
|
||||
plots.append({
|
||||
"name": "J", "type": "line", "data": f"df['kdj_{p}_{si}_j'].tolist()", "color": "#ffc658", "overlay": False
|
||||
})
|
||||
|
||||
elif ind == "macd":
|
||||
f = params.get("fast_period", 12)
|
||||
s = params.get("slow_period", 26)
|
||||
si = params.get("signal_period", 9)
|
||||
plots.append(
|
||||
{
|
||||
"name": "MACD",
|
||||
"type": "line",
|
||||
"data": f"df['macd_{f}_{s}_{si}_line'].tolist()",
|
||||
"color": "#0088FE",
|
||||
"overlay": False,
|
||||
}
|
||||
)
|
||||
plots.append(
|
||||
{
|
||||
"name": "Signal",
|
||||
"type": "line",
|
||||
"data": f"df['macd_{f}_{s}_{si}_signal'].tolist()",
|
||||
"color": "#FF8042",
|
||||
"overlay": False,
|
||||
}
|
||||
)
|
||||
elif ind == "rsi":
|
||||
p = params.get("period", 14)
|
||||
plots.append(
|
||||
{
|
||||
"name": f"RSI {p}",
|
||||
"type": "line",
|
||||
"data": f"df['rsi_{p}'].tolist()",
|
||||
"color": "#8884d8",
|
||||
"overlay": False,
|
||||
}
|
||||
)
|
||||
elif ind == "kdj":
|
||||
p = params.get("period", 9)
|
||||
si = params.get("signal_period", 3)
|
||||
plots.append(
|
||||
{
|
||||
"name": "K",
|
||||
"type": "line",
|
||||
"data": f"df['kdj_{p}_{si}_k'].tolist()",
|
||||
"color": "#8884d8",
|
||||
"overlay": False,
|
||||
}
|
||||
)
|
||||
plots.append(
|
||||
{
|
||||
"name": "D",
|
||||
"type": "line",
|
||||
"data": f"df['kdj_{p}_{si}_d'].tolist()",
|
||||
"color": "#82ca9d",
|
||||
"overlay": False,
|
||||
}
|
||||
)
|
||||
plots.append(
|
||||
{
|
||||
"name": "J",
|
||||
"type": "line",
|
||||
"data": f"df['kdj_{p}_{si}_j'].tolist()",
|
||||
"color": "#ffc658",
|
||||
"overlay": False,
|
||||
}
|
||||
)
|
||||
|
||||
# Convert plots to string representation valid in Python
|
||||
plots_py = "[\n"
|
||||
for p in plots:
|
||||
@@ -685,4 +756,3 @@ output = {{
|
||||
]
|
||||
}}
|
||||
"""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user