second
This commit is contained in:
parent
17199e9a44
commit
b816a42eab
1
.gitignore
vendored
1
.gitignore
vendored
@ -114,6 +114,7 @@ target/
|
||||
!config_examples/config_full.example.json
|
||||
!config_examples/config_kraken.example.json
|
||||
!config_examples/config_freqai.example.json
|
||||
!config_examples/*.json
|
||||
|
||||
docker-compose-*.yml
|
||||
data/
|
||||
|
||||
130
config_examples/config_freqai.okx.json
Normal file
130
config_examples/config_freqai.okx.json
Normal file
@ -0,0 +1,130 @@
|
||||
{
|
||||
"$schema": "https://schema.freqtrade.io/schema.json",
|
||||
"trading_mode": "spot",
|
||||
"margin_mode": "isolated",
|
||||
"max_open_trades": 4,
|
||||
"stake_currency": "USDT",
|
||||
"stake_amount": 150,
|
||||
"tradable_balance_ratio": 1,
|
||||
"fiat_display_currency": "USD",
|
||||
"dry_run": true,
|
||||
"timeframe": "3m",
|
||||
"dry_run_wallet": 1000,
|
||||
"cancel_open_orders_on_exit": true,
|
||||
"stoploss": -0.09,
|
||||
"unfilledtimeout": {
|
||||
"entry": 5,
|
||||
"exit": 15
|
||||
},
|
||||
"exchange": {
|
||||
"name": "okx",
|
||||
"key": "eca767d4-fda5-4a1b-bb28-49ae18093307",
|
||||
"secret": "8CA3628A556ED137977DB298D37BC7F3",
|
||||
"enable_ws": false,
|
||||
"ccxt_config": {
|
||||
"enableRateLimit": true,
|
||||
"rateLimit": 500,
|
||||
"options": {
|
||||
"defaultType": "spot"
|
||||
}
|
||||
},
|
||||
"ccxt_async_config": {
|
||||
"enableRateLimit": true,
|
||||
"rateLimit": 500,
|
||||
"timeout": 20000
|
||||
},
|
||||
"pair_whitelist": [
|
||||
"BTC/USDT",
|
||||
"SOL/USDT"
|
||||
],
|
||||
"pair_blacklist": []
|
||||
},
|
||||
"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"
|
||||
}
|
||||
],
|
||||
"freqai": {
|
||||
"enabled": true,
|
||||
"data_kitchen": {
|
||||
"fillna": "ffill"
|
||||
},
|
||||
"freqaimodel": "CatboostClassifier",
|
||||
"purge_old_models": 2,
|
||||
"train_period_days": 15,
|
||||
"identifier": "test3",
|
||||
"train_period_days": 30,
|
||||
"backtest_period_days": 10,
|
||||
"live_retrain_hours": 0,
|
||||
"feature_selection": {
|
||||
"method": "recursive_elimination"
|
||||
},
|
||||
"feature_parameters": {
|
||||
"include_timeframes": [
|
||||
"3m",
|
||||
"15m",
|
||||
"1h"
|
||||
],
|
||||
"include_corr_pairlist": [
|
||||
"BTC/USDT",
|
||||
"SOL/USDT"
|
||||
],
|
||||
"label_period_candles": 20,
|
||||
"include_shifted_candles": 2,
|
||||
"DI_threshold": 0.9,
|
||||
"weight_factor": 0.9,
|
||||
"principal_component_analysis": false,
|
||||
"use_SVM_to_remove_outliers": false,
|
||||
"indicator_periods_candles": [
|
||||
10,
|
||||
20,
|
||||
50
|
||||
],
|
||||
"plot_feature_importances": 0
|
||||
},
|
||||
"data_split_parameters": {
|
||||
"test_size": 0.2
|
||||
},
|
||||
"model_training_parameters": {
|
||||
"n_estimators": 100,
|
||||
"learning_rate": 0.05,
|
||||
"max_depth": 5,
|
||||
"num_leaves": 31
|
||||
}
|
||||
},
|
||||
"api_server": {
|
||||
"enabled": true,
|
||||
"listen_ip_address": "0.0.0.0",
|
||||
"listen_port": 8080,
|
||||
"verbosity": "error",
|
||||
"enable_openapi": false,
|
||||
"jwt_secret_key": "6a599ab046dbb419014807dffd7b8823bfa7e5df56b17d545485deb87331b4ca",
|
||||
"ws_token": "6O5pBDiRigiZrmIsofaE2rkKMJtf9h8zVQ",
|
||||
"CORS_origins": [],
|
||||
"username": "freqAdmin",
|
||||
"password": "admin"
|
||||
},
|
||||
"bot_name": "freqtrade",
|
||||
"initial_state": "running",
|
||||
"force_entry_enable": false,
|
||||
"internals": {
|
||||
"process_throttle_secs": 5,
|
||||
"heartbeat_interval": 20,
|
||||
"loglevel": "DEBUG"
|
||||
}
|
||||
}
|
||||
@ -22,6 +22,7 @@ services:
|
||||
- "./user_data:/freqtrade/user_data"
|
||||
- "./config_examples:/freqtrade/config_examples"
|
||||
- "./freqtrade/templates:/freqtrade/templates"
|
||||
- "./freqtrade/exchange/:/freqtrade/exchange"
|
||||
# Expose api on port 8080 (localhost only)
|
||||
# Please read the https://www.freqtrade.io/en/stable/rest-api/ documentation
|
||||
# for more information.
|
||||
@ -30,12 +31,23 @@ services:
|
||||
# Default command used when running `docker compose up`
|
||||
|
||||
# --freqaimodel XGBoostRegressor
|
||||
# commangd: >
|
||||
# # trade
|
||||
# --logfile /freqtrade/user_data/logs/freqtrade.log
|
||||
# --db-url sqlite:////freqtrade/user_data/tradesv3.sqlite
|
||||
# --freqaimodel LightGBMRegressor
|
||||
# --config /freqtrade/config_examples/config_freqai.okx.json
|
||||
# --strategy FreqaiExampleStrategy
|
||||
# --strategy FreqaiExampleHybridStrategy
|
||||
# --strategy-path /freqtrade/templates
|
||||
command: >
|
||||
trade
|
||||
backtesting
|
||||
--logfile /freqtrade/user_data/logs/freqtrade.log
|
||||
--db-url sqlite:////freqtrade/user_data/tradesv3.sqlite
|
||||
--freqaimodel LightGBMRegressor
|
||||
--freqaimodel XGBoostRegressor
|
||||
--config /freqtrade/config_examples/config_freqai.okx.json
|
||||
--strategy FreqaiExampleStrategy
|
||||
--strategy-path /freqtrade/templates
|
||||
--strategy FreqaiExampleStrategy
|
||||
--timerange 20250320-20250420
|
||||
--export trades
|
||||
|
||||
|
||||
|
||||
@ -88,13 +88,11 @@ class FreqaiExampleHybridStrategy(IStrategy):
|
||||
stoploss = -0.05
|
||||
use_exit_signal = True
|
||||
startup_candle_count: int = 30
|
||||
can_short = True
|
||||
can_short = False
|
||||
|
||||
# Hyperoptable parameters
|
||||
buy_rsi = IntParameter(low=1, high=50, default=30, space="buy", optimize=True, load=True)
|
||||
sell_rsi = IntParameter(low=50, high=100, default=70, space="sell", optimize=True, load=True)
|
||||
short_rsi = IntParameter(low=51, high=100, default=70, space="sell", optimize=True, load=True)
|
||||
exit_short_rsi = IntParameter(low=1, high=50, default=30, space="buy", optimize=True, load=True)
|
||||
|
||||
def feature_engineering_expand_all(
|
||||
self, dataframe: DataFrame, period: int, metadata: dict, **kwargs
|
||||
@ -210,35 +208,65 @@ class FreqaiExampleHybridStrategy(IStrategy):
|
||||
dataframe["%-day_of_week"] = dataframe["date"].dt.dayofweek
|
||||
dataframe["%-hour_of_day"] = dataframe["date"].dt.hour
|
||||
return dataframe
|
||||
|
||||
def set_freqai_targets(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
|
||||
"""
|
||||
*Only functional with FreqAI enabled strategies*
|
||||
Required function to set the targets for the model.
|
||||
All targets must be prepended with `&` to be recognized by the FreqAI internals.
|
||||
logger.info(f"Setting FreqAI targets for pair: {metadata['pair']}")
|
||||
logger.info(f"DataFrame shape: {dataframe.shape}")
|
||||
logger.info(f"Available columns: {list(dataframe.columns)}")
|
||||
logger.info(f"First few rows:\n{dataframe[['date', 'close']].head().to_string()}")
|
||||
|
||||
More details about feature engineering available:
|
||||
if "close" not in dataframe.columns:
|
||||
logger.error("Required 'close' column missing in dataframe")
|
||||
raise ValueError("Required 'close' column missing in dataframe")
|
||||
|
||||
https://www.freqtrade.io/en/latest/freqai-feature-engineering
|
||||
if len(dataframe) < 50:
|
||||
logger.error(f"Insufficient data: {len(dataframe)} rows, need at least 50 for shift(-50)")
|
||||
raise ValueError("Insufficient data for target calculation")
|
||||
|
||||
:param dataframe: strategy dataframe which will receive the targets
|
||||
:param metadata: metadata of current pair
|
||||
usage example: dataframe["&-target"] = dataframe["close"].shift(-1) / dataframe["close"]
|
||||
"""
|
||||
self.freqai.class_names = ["down", "up"]
|
||||
dataframe["&s-up_or_down"] = np.where(
|
||||
dataframe["close"].shift(-50) > dataframe["close"], "up", "down"
|
||||
try:
|
||||
# 生成数值型标签:1 表示上涨,0 表示下跌
|
||||
dataframe["&-up_or_down"] = np.where(
|
||||
dataframe["close"].shift(-50) > dataframe["close"],
|
||||
1.0, # 数值型标签
|
||||
0.0
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to create &-up_or_down column: {str(e)}")
|
||||
raise
|
||||
|
||||
logger.info(f"Target column head:\n{dataframe[['&-up_or_down']].head().to_string()}")
|
||||
|
||||
if "&-up_or_down" not in dataframe.columns:
|
||||
logger.error("FreqAI failed to generate the &-up_or_down column")
|
||||
raise KeyError("FreqAI failed to generate the &-up_or_down column")
|
||||
|
||||
logger.info("FreqAI targets set successfully")
|
||||
return dataframe
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # noqa: C901
|
||||
# User creates their own custom strat here. Present example is a supertrend
|
||||
# based strategy.
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
logger.info(f"Processing pair: {metadata['pair']}")
|
||||
logger.info(f"Input DataFrame shape: {dataframe.shape}")
|
||||
logger.info(f"Input DataFrame columns: {list(dataframe.columns)}")
|
||||
logger.info(f"Input DataFrame head:\n{dataframe[['date', 'close', 'volume']].head().to_string()}")
|
||||
|
||||
# Ensure FreqAI processing
|
||||
logger.info("Calling self.freqai.start")
|
||||
try:
|
||||
dataframe = self.freqai.start(dataframe, metadata, self)
|
||||
except Exception as e:
|
||||
logger.error(f"self.freqai.start failed: {str(e)}")
|
||||
raise
|
||||
logger.info("self.freqai.start completed")
|
||||
|
||||
logger.info(f"Output DataFrame shape: {dataframe.shape}")
|
||||
logger.info(f"Output DataFrame columns: {list(dataframe.columns)}")
|
||||
# Safely log columns that exist
|
||||
available_columns = [col for col in ['date', 'close', '&-up_or_down'] if col in dataframe.columns]
|
||||
logger.info(f"Output DataFrame head:\n{dataframe[available_columns].head().to_string()}")
|
||||
|
||||
if "&-up_or_down" not in dataframe.columns:
|
||||
logger.error("FreqAI did not generate the required &-up_or_down column")
|
||||
raise KeyError("FreqAI did not generate the required &-up_or_down column")
|
||||
|
||||
# TA indicators to combine with the Freqai targets
|
||||
# RSI
|
||||
dataframe["rsi"] = ta.RSI(dataframe)
|
||||
|
||||
@ -254,67 +282,30 @@ class FreqaiExampleHybridStrategy(IStrategy):
|
||||
"bb_middleband"
|
||||
]
|
||||
|
||||
# TEMA - Triple Exponential Moving Average
|
||||
# TEMA
|
||||
dataframe["tema"] = ta.TEMA(dataframe, timeperiod=9)
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
|
||||
df.loc[
|
||||
(
|
||||
# Signal: RSI crosses above 30
|
||||
(qtpylib.crossed_above(df["rsi"], self.buy_rsi.value))
|
||||
& (df["tema"] <= df["bb_middleband"]) # Guard: tema below BB middle
|
||||
& (df["tema"] > df["tema"].shift(1)) # Guard: tema is raising
|
||||
& (df["volume"] > 0) # Make sure Volume is not 0
|
||||
& (df["do_predict"] == 1) # Make sure Freqai is confident in the prediction
|
||||
&
|
||||
# Only enter trade if Freqai thinks the trend is in this direction
|
||||
(df["&s-up_or_down"] == "up")
|
||||
& (df["tema"] <= df["bb_middleband"])
|
||||
& (df["tema"] > df["tema"].shift(1))
|
||||
& (df["volume"] > 0)
|
||||
),
|
||||
"enter_long",
|
||||
] = 1
|
||||
|
||||
df.loc[
|
||||
(
|
||||
# Signal: RSI crosses above 70
|
||||
(qtpylib.crossed_above(df["rsi"], self.short_rsi.value))
|
||||
& (df["tema"] > df["bb_middleband"]) # Guard: tema above BB middle
|
||||
& (df["tema"] < df["tema"].shift(1)) # Guard: tema is falling
|
||||
& (df["volume"] > 0) # Make sure Volume is not 0
|
||||
& (df["do_predict"] == 1) # Make sure Freqai is confident in the prediction
|
||||
&
|
||||
# Only enter trade if Freqai thinks the trend is in this direction
|
||||
(df["&s-up_or_down"] == "down")
|
||||
),
|
||||
"enter_short",
|
||||
] = 1
|
||||
|
||||
return df
|
||||
|
||||
def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
|
||||
df.loc[
|
||||
(
|
||||
# Signal: RSI crosses above 70
|
||||
(qtpylib.crossed_above(df["rsi"], self.sell_rsi.value))
|
||||
& (df["tema"] > df["bb_middleband"]) # Guard: tema above BB middle
|
||||
& (df["tema"] < df["tema"].shift(1)) # Guard: tema is falling
|
||||
& (df["volume"] > 0) # Make sure Volume is not 0
|
||||
& (df["tema"] > df["bb_middleband"])
|
||||
& (df["tema"] < df["tema"].shift(1))
|
||||
& (df["volume"] > 0)
|
||||
),
|
||||
"exit_long",
|
||||
] = 1
|
||||
|
||||
df.loc[
|
||||
(
|
||||
# Signal: RSI crosses above 30
|
||||
(qtpylib.crossed_above(df["rsi"], self.exit_short_rsi.value))
|
||||
&
|
||||
# Guard: tema below BB middle
|
||||
(df["tema"] <= df["bb_middleband"])
|
||||
& (df["tema"] > df["tema"].shift(1)) # Guard: tema is raising
|
||||
& (df["volume"] > 0) # Make sure Volume is not 0
|
||||
),
|
||||
"exit_short",
|
||||
] = 1
|
||||
|
||||
return df
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user