回测结果还不错的一个版本, 但是grok说还能更优化, 结果优化完了不如现在, 但是我我先存一个版本
This commit is contained in:
parent
1ea7d2ec75
commit
8d479752ee
2
.gitignore
vendored
2
.gitignore
vendored
@ -75,6 +75,8 @@ coverage.xml
|
||||
# Django stuff:
|
||||
#*.log
|
||||
!outout_filted.log
|
||||
!result/outout_filted.log
|
||||
!result/outout.log
|
||||
|
||||
local_settings.py
|
||||
|
||||
|
||||
2
aaa
Normal file
2
aaa
Normal file
@ -0,0 +1,2 @@
|
||||
https://www.freqtrade.io/en/stable/strategy/custom-stakeamount/
|
||||
|
||||
@ -2,10 +2,24 @@
|
||||
"$schema": "https://schema.freqtrade.io/schema.json",
|
||||
"trading_mode": "spot",
|
||||
"margin_mode": "isolated",
|
||||
"max_open_trades": 4,
|
||||
"max_open_trades": 3,
|
||||
"stake_amount": 300,
|
||||
"unfilledtimeout": {
|
||||
"entry": 10,
|
||||
"exit": 20
|
||||
},
|
||||
"entry_pricing": {
|
||||
"price_side": "same",
|
||||
"use_order_book": true,
|
||||
"order_book_top": 1
|
||||
},
|
||||
"exit_pricing": {
|
||||
"price_side": "other",
|
||||
"use_order_book": true,
|
||||
"order_book_top": 1
|
||||
},
|
||||
"stake_currency": "USDT",
|
||||
"stake_amount": 150,
|
||||
"startup_candle_count": 400,
|
||||
"startup_candle_count": 200,
|
||||
"tradable_balance_ratio": 1,
|
||||
"fiat_display_currency": "USD",
|
||||
"dry_run": true,
|
||||
@ -14,14 +28,10 @@
|
||||
"dry_run_wallet": 1000,
|
||||
"cancel_open_orders_on_exit": true,
|
||||
"stoploss": -0.1,
|
||||
"unfilledtimeout": {
|
||||
"entry": 5,
|
||||
"exit": 15
|
||||
},
|
||||
"exchange": {
|
||||
"name": "okx",
|
||||
"key": "eca767d4-fda5-4a1b-bb28-49ae18093307",
|
||||
"secret": "8CA3628A556ED137977DB298D37BC7F3",
|
||||
"key": "REDACTED",
|
||||
"secret": "REDACTED",
|
||||
"enable_ws": false,
|
||||
"ccxt_config": {
|
||||
"enableRateLimit": true,
|
||||
@ -32,77 +42,12 @@
|
||||
},
|
||||
"ccxt_async_config": {
|
||||
"enableRateLimit": true,
|
||||
"rateLimit": 3000,
|
||||
"rateLimit": 3000,
|
||||
"timeout": 20000
|
||||
},
|
||||
"pair_whitelist": [
|
||||
"OKB/USDT",
|
||||
"BTC/USDT",
|
||||
"ETH/USDT",
|
||||
"SOL/USDT",
|
||||
"DOT/USDT"
|
||||
],
|
||||
"pair_whitelist": ["OKB/USDT", "BTC/USDT", "ETH/USDT", "SOL/USDT"],
|
||||
"pair_blacklist": []
|
||||
},
|
||||
"freqai": {
|
||||
"enabled": true,
|
||||
"identifier": "test175",
|
||||
"freqaimodel": "XGBoostRegressor",
|
||||
"model_path": "/freqtrade/user_data/models",
|
||||
"save_backtesting_prediction": true,
|
||||
"save_backtest_models": true,
|
||||
"backtest_period_days": 30,
|
||||
"purge_old_models": true,
|
||||
"load_trained_model": true,
|
||||
"train_period_days": 90,
|
||||
"backtest_period_days": 10,
|
||||
"live_retrain_hours": 0,
|
||||
"include_predictions_in_final_dataframe": true,
|
||||
"data_kitchen": {
|
||||
"fillna": "ffill",
|
||||
"feature_parameters": {
|
||||
"DI_threshold": 0.5,
|
||||
"weight_factor": 0.9
|
||||
}
|
||||
},
|
||||
"feature_parameters": {
|
||||
"include_timeframes": ["5m", "15m", "1h"],
|
||||
"include_corr_pairlist": ["BTC/USDT", "ETH/USDT"],
|
||||
"label_period_candles": 12,
|
||||
"include_shifted_candles": 3,
|
||||
"indicator_periods_candles": [10, 20, 50],
|
||||
"plot_feature_importances": 1,
|
||||
"feature_selection": {
|
||||
"method": "none"
|
||||
}
|
||||
},
|
||||
"data_split_parameters": {
|
||||
"test_size": 0.2,
|
||||
"shuffle": false
|
||||
},
|
||||
"model_training_parameters": {
|
||||
"n_estimators": 200,
|
||||
"learning_rate": 0.05,
|
||||
"max_depth": 6,
|
||||
"subsample": 0.8,
|
||||
"colsample_bytree": 0.8
|
||||
}
|
||||
},
|
||||
"entry_pricing": {
|
||||
"price_side": "same",
|
||||
"use_order_book": true,
|
||||
"order_book_top": 1,
|
||||
"price_last_balance": 0.0,
|
||||
"check_depth_of_market": {
|
||||
"enabled": false,
|
||||
"bids_to_ask_delta": 1
|
||||
}
|
||||
},
|
||||
"exit_pricing": {
|
||||
"price_side": "other",
|
||||
"use_order_book": true,
|
||||
"order_book_top": 1
|
||||
},
|
||||
"pairlists": [
|
||||
{
|
||||
"method": "StaticPairList"
|
||||
@ -118,7 +63,7 @@
|
||||
"ws_token": "6O5pBDiRigiZrmIsofaE2rkKMJtf9h8zVQ",
|
||||
"CORS_origins": [],
|
||||
"username": "freqAdmin",
|
||||
"password": "admin"
|
||||
"password": "REDACTED"
|
||||
},
|
||||
"use_exit_signal": true,
|
||||
"bot_name": "freqtrade",
|
||||
@ -127,6 +72,7 @@
|
||||
"internals": {
|
||||
"process_throttle_secs": 5,
|
||||
"heartbeat_interval": 20,
|
||||
"loglevel": "DEBUG"
|
||||
}
|
||||
"loglevel": "INFO"
|
||||
},
|
||||
"config_files": ["config_examples/theforcev7.json"]
|
||||
}
|
||||
|
||||
@ -1,201 +1,121 @@
|
||||
from freqtrade.strategy import IStrategy
|
||||
from pandas import DataFrame
|
||||
import numpy as np
|
||||
import os
|
||||
import datetime
|
||||
import time
|
||||
import pandas as pd
|
||||
import talib.abstract as ta
|
||||
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||
from freqtrade.persistence import Trade # 必须导入 Trade 类
|
||||
from tempfile import NamedTemporaryFile
|
||||
import shutil
|
||||
|
||||
from typing import Optional, Union
|
||||
from freqtrade.persistence import Trade
|
||||
from datetime import datetime
|
||||
|
||||
class TheForceV7(IStrategy):
|
||||
INTERFACE_VERSION = 3
|
||||
|
||||
minimal_roi = {
|
||||
"0": 10
|
||||
}
|
||||
stoploss = -0.1
|
||||
trailing_stop = False
|
||||
timeframe = '5m'
|
||||
process_only_new_candles = True
|
||||
use_exit_signal = True
|
||||
ignore_roi_if_entry_signal = True
|
||||
startup_candle_count: int = 30
|
||||
order_types = {
|
||||
'entry': 'limit',
|
||||
'exit': 'limit',
|
||||
'stoploss': 'market',
|
||||
'stoploss_on_exchange': False
|
||||
}
|
||||
order_time_in_force = {
|
||||
'entry': 'gtc',
|
||||
'exit': 'gtc'
|
||||
}
|
||||
|
||||
plot_config = {
|
||||
'main_plot': {
|
||||
'tema': {},
|
||||
'sar': {'color': 'white'},
|
||||
},
|
||||
'subplots': {
|
||||
"MACD": {
|
||||
'macd': {'color': 'blue'},
|
||||
'macdsignal': {'color': 'orange'},
|
||||
},
|
||||
"RSI": {
|
||||
'rsi': {'color': 'red'},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def __init__(self, config: dict) -> None:
|
||||
super().__init__(config)
|
||||
self.trade_data = {} # 用于缓存 K 线数据以计算 min_rate 和 max_rate
|
||||
|
||||
def informative_pairs(self):
|
||||
return []
|
||||
# Strategy configuration
|
||||
timeframe = "5m"
|
||||
minimal_roi = {"0": 0.02} # 2% ROI for realistic take-profit
|
||||
stoploss = -0.1 # Fallback, overridden by custom_exit
|
||||
startup_candle_count = 200 # Reduced for indicator calculations
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
# 缓存 K 线数据
|
||||
self.trade_data[metadata['pair']] = dataframe
|
||||
|
||||
stoch = ta.STOCH(dataframe)
|
||||
dataframe['slowd'] = stoch['slowd']
|
||||
dataframe['slowk'] = stoch['slowk']
|
||||
|
||||
dataframe['rsi7'] = ta.RSI(dataframe, timeperiod=7)
|
||||
|
||||
macd = ta.MACD(dataframe, 12, 26, 1)
|
||||
dataframe['macd'] = macd['macd']
|
||||
dataframe['macdsignal'] = macd['macdsignal']
|
||||
dataframe['macdhist'] = macd['macdhist']
|
||||
|
||||
dataframe['ema5h'] = ta.EMA(dataframe['high'], timeperiod=5)
|
||||
dataframe['ema5l'] = ta.EMA(dataframe['low'], timeperiod=5)
|
||||
dataframe['ema5c'] = ta.EMA(dataframe['close'], timeperiod=5)
|
||||
dataframe['ema5o'] = ta.EMA(dataframe['open'], timeperiod=5)
|
||||
dataframe['ema200c'] = ta.MA(dataframe['close'], 200)
|
||||
|
||||
dataframe['volvar'] = (dataframe['volume'].rolling(100).mean() * 1.5)
|
||||
|
||||
bollinger = qtpylib.bollinger_bands(dataframe['close'], window=21, stds=2)
|
||||
dataframe['bb_lowerband'] = bollinger['lower']
|
||||
dataframe['bb_upperband'] = bollinger['upper']
|
||||
dataframe['bb_middleband'] = bollinger['mid']
|
||||
dataframe['ema200c'] = ta.EMA(dataframe['close'], timeperiod=200)
|
||||
dataframe['ema50c'] = ta.EMA(dataframe['close'], timeperiod=50)
|
||||
dataframe['ema20c'] = ta.EMA(dataframe['close'], timeperiod=20)
|
||||
dataframe['rsi7'] = ta.RSI(dataframe['close'], timeperiod=7)
|
||||
macd = ta.MACD(dataframe['close'])
|
||||
dataframe['macd'] = macd[0]
|
||||
dataframe['macdsignal'] = macd[1]
|
||||
stoch = ta.STOCH(dataframe['high'], dataframe['low'], dataframe['close'], fastk_period=14, slowk_period=3, slowd_period=3)
|
||||
dataframe['slowk'] = stoch[0]
|
||||
dataframe['slowd'] = stoch[1]
|
||||
dataframe['adx'] = ta.ADX(dataframe['high'], dataframe['low'], dataframe['close'], timeperiod=14)
|
||||
dataframe['volvar'] = dataframe['volume'].rolling(window=20).mean()
|
||||
|
||||
return dataframe
|
||||
|
||||
def crossover(self, series1: DataFrame, series2: DataFrame) -> DataFrame:
|
||||
"""Detects when series1 crosses above series2."""
|
||||
return (series1 > series2) & (series1.shift(1) <= series2.shift(1))
|
||||
|
||||
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
dataframe.loc[
|
||||
(
|
||||
(
|
||||
(
|
||||
(dataframe['slowk'] >= 20) & (dataframe['slowk'] <= 80)
|
||||
&
|
||||
(dataframe['slowd'] >= 20) & (dataframe['slowd'] <= 80)
|
||||
)
|
||||
|
|
||||
(
|
||||
(dataframe['slowk'] < 30) & (dataframe['slowd'] < 30) &
|
||||
(qtpylib.crossed_above(dataframe['slowk'], dataframe['slowd']))
|
||||
)
|
||||
)
|
||||
&
|
||||
(
|
||||
(dataframe['macd'] > dataframe['macd'].shift(1))
|
||||
&
|
||||
(dataframe['macdsignal'] > dataframe['macdsignal'].shift(1))
|
||||
)
|
||||
&
|
||||
(
|
||||
(dataframe['close'] > dataframe['close'].shift(1))
|
||||
&
|
||||
(dataframe['open'] > dataframe['open'].shift(1))
|
||||
)
|
||||
&
|
||||
(
|
||||
(dataframe['ema5c'] >= dataframe['ema5o'])
|
||||
|
|
||||
(dataframe['open'] < dataframe['ema5l'])
|
||||
)
|
||||
&
|
||||
(
|
||||
(dataframe['volume'] > dataframe['volvar'])
|
||||
)
|
||||
|
|
||||
(
|
||||
(dataframe['slowk'] >= 20) & (dataframe['slowk'] <= 80)
|
||||
&
|
||||
(dataframe['slowd'] >= 20) & (dataframe['slowd'] <= 80)
|
||||
&
|
||||
(
|
||||
(dataframe['close'] <= dataframe['bb_lowerband'])
|
||||
|
|
||||
(dataframe['open'] <= dataframe['bb_lowerband'])
|
||||
)
|
||||
)
|
||||
|
|
||||
(
|
||||
(dataframe['close'] > dataframe['ema200c'])
|
||||
&
|
||||
(dataframe['rsi7'] < 35)
|
||||
)
|
||||
),
|
||||
'enter_long'] = 1
|
||||
(dataframe['close'] > dataframe['ema200c']) & # Relaxed trend
|
||||
(dataframe['close'] > dataframe['ema50c']) & # Short-term trend
|
||||
(dataframe['rsi7'] < 50) & # Relaxed RSI
|
||||
(dataframe['macd'] > 0) & # Relaxed MACD
|
||||
(dataframe['volume'] > dataframe['volvar'] * 0.5) & # Relaxed volume
|
||||
(dataframe['adx'] > 20), # Trend strength
|
||||
'enter_long'
|
||||
] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
|
||||
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
dataframe.loc[
|
||||
(
|
||||
(
|
||||
(
|
||||
(dataframe['slowk'] <= 80) & (dataframe['slowd'] <= 80)
|
||||
)
|
||||
|
|
||||
(
|
||||
(qtpylib.crossed_above(dataframe['slowk'], 70))
|
||||
|
|
||||
(qtpylib.crossed_above(dataframe['slowd'], 70))
|
||||
)
|
||||
)
|
||||
&
|
||||
(
|
||||
(dataframe['macd'] < dataframe['macd'].shift(1))
|
||||
&
|
||||
(dataframe['macdsignal'] < dataframe['macdsignal'].shift(1))
|
||||
)
|
||||
&
|
||||
(
|
||||
(dataframe['ema5c'] < dataframe['ema5o'])
|
||||
|
|
||||
(dataframe['open'] >= dataframe['ema5h'])
|
||||
)
|
||||
|
|
||||
(
|
||||
(dataframe['slowk'] <= 80)
|
||||
&
|
||||
(dataframe['slowd'] <= 80)
|
||||
&
|
||||
(
|
||||
(dataframe['close'] >= dataframe['bb_upperband'])
|
||||
|
|
||||
(dataframe['open'] >= dataframe['bb_upperband'])
|
||||
)
|
||||
)
|
||||
|
|
||||
(
|
||||
(dataframe['high'] > dataframe['bb_upperband'])
|
||||
&
|
||||
(((dataframe['high'] - dataframe['bb_upperband']) * 100 / dataframe['bb_upperband']) > 1)
|
||||
)
|
||||
),
|
||||
'exit_long'] = 1
|
||||
(dataframe['slowk'] > 65) | (dataframe['slowd'] > 65) | # Relaxed STOCH
|
||||
(dataframe['rsi7'] > 70) # Overbought
|
||||
) &
|
||||
(dataframe['close'] < dataframe['ema20c']) & # Trend reversal
|
||||
(self.crossover(dataframe['macdsignal'], dataframe['macd'])) & # Custom crossover
|
||||
(dataframe['macd'] < 0), # Downtrend
|
||||
'exit_long'
|
||||
] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
def custom_exit(self, pair: str, trade: Trade, current_time: datetime, current_rate: float,
|
||||
current_profit: float, **kwargs) -> Optional[Union[str, bool]]:
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
if dataframe.empty or dataframe['date'].iloc[-1] < current_time: # Fixed: Use date column
|
||||
return None
|
||||
|
||||
last_candle = dataframe.iloc[-1]
|
||||
atr = ta.ATR(dataframe, timeperiod=14).iloc[-1]
|
||||
duration = (current_time - trade.open_date).total_seconds() / 60 # Minutes
|
||||
|
||||
# Dynamic Take-Profit
|
||||
take_profit = current_rate + 1.0 * atr # Lowered ATR
|
||||
if current_rate >= take_profit:
|
||||
return "take_profit"
|
||||
|
||||
# Partial Take-Profit at 2%
|
||||
if current_profit >= 0.02:
|
||||
return "partial_take_profit"
|
||||
|
||||
# Dynamic Stop-Loss
|
||||
stop_loss = current_rate - 2.0 * atr # Relaxed ATR
|
||||
if current_rate <= stop_loss:
|
||||
return "dynamic_stop_loss"
|
||||
|
||||
# Trailing Stop
|
||||
if current_profit > 0.005: # Lowered threshold
|
||||
self.trailing_stop = True
|
||||
self.trailing_stop_positive = 0.003 # 0.3% retracement
|
||||
self.trailing_stop_positive_offset = 0.008 # 0.8% offset
|
||||
if current_profit < trade.max_profit - self.trailing_stop_positive:
|
||||
return "trailing_stop"
|
||||
|
||||
# Time Stop
|
||||
if duration > 60: # 1 hour
|
||||
return "time_stop"
|
||||
|
||||
return None
|
||||
|
||||
def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float,
|
||||
proposed_stake: float, min_stake: float, max_stake: float,
|
||||
leverage: float, entry_tag: Optional[str], side: str,
|
||||
**kwargs) -> float:
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
if dataframe.empty:
|
||||
return proposed_stake
|
||||
|
||||
atr = ta.ATR(dataframe, timeperiod=14).iloc[-1]
|
||||
price_std = dataframe['close'].std()
|
||||
combined_volatility = atr + price_std
|
||||
|
||||
base_stake = self.wallets.get_total_stake_amount() * 0.0333 # 3.33% risk
|
||||
base_stake = min(base_stake, 50.0) # Cap at 50 USDT
|
||||
|
||||
risk_factor = 1.0
|
||||
if combined_volatility > current_rate * 0.03: # High volatility
|
||||
risk_factor = 0.3 if pair in ['SOL/USDT', 'OKB/USDT'] else 0.5
|
||||
elif combined_volatility < current_rate * 0.01: # Low volatility
|
||||
risk_factor = 1.2 if pair in ['BTC/USDT', 'ETH/USDT'] else 1.0
|
||||
|
||||
return base_stake * risk_factor
|
||||
|
||||
@ -67,7 +67,7 @@ fi
|
||||
cd -
|
||||
sed -i 's/\x1B\[[0-9;]*m//g' output.log
|
||||
#python3 ../filter.py
|
||||
cp output_filted.log result/ -f
|
||||
cp output.log result/ -f
|
||||
cd tools/
|
||||
python tradestocsv.py
|
||||
cd ../
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user