# source: https://raw.githubusercontent.com/CETANGZHI/flowainew/94cc7095db1259c5f1cb053bdf5c74bb0c4c16c3/backend/scripts/seed_public_strategies.py
"""Seed a set of public trading strategies for the strategy library.

Usage (from backend directory):

    uvicorn app.main:app --reload  # make sure DB is up
    python -m app.scripts.seed_public_strategies

This script is idempotent: if a strategy with the same name already exists,
it will be skipped.
"""

from __future__ import annotations

import logging
from typing import List

from sqlalchemy.orm import Session

from app.database import SessionLocal
from app.models.database import Strategy, User

logger = logging.getLogger(__name__)


SEED_OWNER_EMAIL = "public-strategy-seeder@local"


def get_or_create_seed_user(db: Session) -> User:
    """Return a dedicated user to own seeded public strategies.

    The user is not intended for login, only as a logical owner of
    global public strategies.
    """

    user = (
        db.query(User)
        .filter(User.email == SEED_OWNER_EMAIL, User.deleted_at.is_(None))
        .first()
    )
    if user:
        return user

    logger.info("Creating seed user %s", SEED_OWNER_EMAIL)
    user = User(
        email=SEED_OWNER_EMAIL,
        password_hash=None,
        name="Public Strategy Seeder",
        is_active=True,
        is_verified=False,
    )
    db.add(user)
    db.commit()
    db.refresh(user)
    return user


def seed_strategies(db: Session, owner: User) -> None:
    """Insert a set of example public strategies.

    Only name / description / pairs / timeframe / code / stats are seeded.
    If a strategy with the same name already exists, it is skipped.
    """

    # NOTE: these are simple, valid Freqtrade-style templates with different
    # flavours (trend following, mean reversion, breakout, volatility, etc.).
    # Users are expected to further optimise them via the Strategy Lab.

    base_pairs = ["BTC/USDT"]

    seeds: List[dict] = [
        {
            "name": "BTC 趋势跟随 1h",
            "description": "基于 EMA 交叉和成交量过滤的 BTC/USDT 1 小时趋势跟随策略。",
            "pairs": base_pairs,
            "timeframe": "1h",
            "code": _SIMPLE_TREND_STRATEGY,
            "avg_profit": 25.4,
            "backtest_count": 12,
        },
        {
            "name": "BTC 区间震荡 4h",
            "description": "使用 RSI 和布林带识别震荡区间，在超卖买入、超买卖出。",
            "pairs": base_pairs,
            "timeframe": "4h",
            "code": _RANGE_MEAN_REVERSION_STRATEGY,
            "avg_profit": 18.7,
            "backtest_count": 9,
        },
        {
            "name": "BTC 突破跟随 1h",
            "description": "价格突破近期高点同时放量时顺势入场，追踪止损保护利润。",
            "pairs": base_pairs,
            "timeframe": "1h",
            "code": _BREAKOUT_STRATEGY,
            "avg_profit": 32.1,
            "backtest_count": 7,
        },
        {
            "name": "BTC 波动率收缩 1h",
            "description": "结合 ATR 波动率收缩与放量突破，捕捉趋势起点。",
            "pairs": base_pairs,
            "timeframe": "1h",
            "code": _VOLATILITY_CONTRACTION_STRATEGY,
            "avg_profit": 21.3,
            "backtest_count": 6,
        },
        {
            "name": "BTC 日内反转 30m",
            "description": "30 分钟级别的日内短线反转策略，利用前一日高低点与短期 RSI。",
            "pairs": base_pairs,
            "timeframe": "30m",
            "code": _INTRADAY_REVERSAL_STRATEGY,
            "avg_profit": 15.6,
            "backtest_count": 10,
        },
        {
            "name": "ETH 趋势跟随 1h",
            "description": "将 BTC 趋势模板迁移到 ETH/USDT，适合中短线趋势持有。",
            "pairs": ["ETH/USDT"],
            "timeframe": "1h",
            "code": _SIMPLE_TREND_STRATEGY,
            "avg_profit": 27.8,
            "backtest_count": 8,
        },
        {
            "name": "ETH 区间震荡 4h",
            "description": "ETH/USDT 4 小时级别的 RSI + 布林带震荡策略。",
            "pairs": ["ETH/USDT"],
            "timeframe": "4h",
            "code": _RANGE_MEAN_REVERSION_STRATEGY,
            "avg_profit": 17.2,
            "backtest_count": 5,
        },
        {
            "name": "BNB 趋势跟随 1h",
            "description": "适配 BNB/USDT 的 EMA 趋势策略，降低交易频率，适合波段。",
            "pairs": ["BNB/USDT"],
            "timeframe": "1h",
            "code": _SIMPLE_TREND_STRATEGY,
            "avg_profit": 19.9,
            "backtest_count": 4,
        },
        {
            "name": "多币种动量轮动 日线",
            "description": "在 BTC/ETH/BNB 之间按最近 N 日动量轮动持仓，偏中长期。",
            "pairs": ["BTC/USDT", "ETH/USDT", "BNB/USDT"],
            "timeframe": "1d",
            "code": _MOMENTUM_ROTATION_STRATEGY,
            "avg_profit": 28.5,
            "backtest_count": 11,
        },
        {
            "name": "稳健现货网格 日线",
            "description": "针对 BTC/USDT 的简化现货网格模板，适合作为学习示例。",
            "pairs": base_pairs,
            "timeframe": "1d",
            "code": _SIMPLE_GRID_STRATEGY,
            "avg_profit": 12.3,
            "backtest_count": 6,
        },
    ]

    created = 0
    for seed in seeds:
        exists = (
            db.query(Strategy)
            .filter(
                Strategy.name == seed["name"],
                Strategy.deleted_at.is_(None),
            )
            .first()
        )
        if exists:
            logger.info("Strategy '%s' already exists, skip", seed["name"])
            continue

        logger.info("Creating public strategy: %s", seed["name"])
        strategy = Strategy(
            user_id=owner.id,
            name=seed["name"],
            description=seed["description"],
            code=seed["code"],
            pairs=seed["pairs"],
            timeframe=seed["timeframe"],
            is_public=True,
            is_active=True,
            backtest_count=seed["backtest_count"],
            avg_profit=seed["avg_profit"],
        )
        db.add(strategy)
        created += 1

    if created:
        db.commit()

    logger.info("Seeded %d new public strategies", created)


def main() -> None:
    logging.basicConfig(level=logging.INFO)
    db = SessionLocal()
    try:
        owner = get_or_create_seed_user(db)
        seed_strategies(db, owner)
    finally:
        db.close()


# --- Strategy code templates ---

_SIMPLE_TREND_STRATEGY = """from freqtrade.strategy.interface import IStrategy
from pandas import DataFrame


class Github_CETANGZHI_flowainew__seed_public_strategies__20260114_114646(IStrategy):
    """简单 EMA 趋势跟随模板，用作公共策略示例。"""

    minimal_roi = {
        "0": 0.10,
        "60": 0.05,
        "240": 0.02,
        "720": 0
    }

    stoploss = -0.15
    timeframe = "1h"

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["ema_fast"] = dataframe["close"].ewm(span=12, adjust=False).mean()
        dataframe["ema_slow"] = dataframe["close"].ewm(span=26, adjust=False).mean()
        dataframe["volume_mean"] = dataframe["volume"].rolling(20).mean()
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe["ema_fast"] > dataframe["ema_slow"]) &
                (dataframe["volume"] > dataframe["volume_mean"]) &
                (dataframe["close"] > dataframe["ema_fast"]) &
                (dataframe["volume"] > 0)
            ),
            "enter_long",
        ] = 1
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe["ema_fast"] < dataframe["ema_slow"]) |
                (dataframe["close"] < dataframe["ema_slow"])
            ),
            "exit_long",
        ] = 1
        return dataframe
"""


_RANGE_MEAN_REVERSION_STRATEGY = """from freqtrade.strategy.interface import IStrategy
from pandas import DataFrame
import talib.abstract as ta


class Github_CETANGZHI_flowainew__seed_public_strategies__20260114_114646(IStrategy):
    """RSI + 布林带震荡区间回归策略示例。"""

    minimal_roi = {
        "0": 0.06,
        "120": 0.03,
        "480": 0
    }

    stoploss = -0.12
    timeframe = "4h"

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        bollinger = ta.BBANDS(dataframe["close"], timeperiod=20)
        dataframe["bb_upper"] = bollinger[0]
        dataframe["bb_middle"] = bollinger[1]
        dataframe["bb_lower"] = bollinger[2]
        dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe["close"] < dataframe["bb_lower"]) &
                (dataframe["rsi"] < 30)
            ),
            "enter_long",
        ] = 1
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe["close"] > dataframe["bb_middle"]) |
                (dataframe["rsi"] > 60)
            ),
            "exit_long",
        ] = 1
        return dataframe
"""


_BREAKOUT_STRATEGY = """from freqtrade.strategy.interface import IStrategy
from pandas import DataFrame


class Github_CETANGZHI_flowainew__seed_public_strategies__20260114_114646(IStrategy):
    """基于近期高点突破的简化模板。"""

    minimal_roi = {
        "0": 0.08,
        "120": 0.04,
        "360": 0
    }

    stoploss = -0.13
    timeframe = "1h"

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["recent_high"] = dataframe["high"].rolling(48).max()
        dataframe["recent_low"] = dataframe["low"].rolling(48).min()
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe["close"] > dataframe["recent_high"].shift(1)) &
                (dataframe["volume"] > dataframe["volume"].rolling(24).mean())
            ),
            "enter_long",
        ] = 1
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe["close"] < dataframe["recent_low"].shift(1))
            ),
            "exit_long",
        ] = 1
        return dataframe
"""


_VOLATILITY_CONTRACTION_STRATEGY = """from freqtrade.strategy.interface import IStrategy
from pandas import DataFrame
import talib.abstract as ta


class Github_CETANGZHI_flowainew__seed_public_strategies__20260114_114646(IStrategy):
    """ATR 波动率收缩 + 放量突破策略示例。"""

    minimal_roi = {
        "0": 0.10,
        "180": 0.05,
        "720": 0
    }

    stoploss = -0.14
    timeframe = "1h"

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["atr"] = ta.ATR(dataframe, timeperiod=14)
        dataframe["atr_sma"] = dataframe["atr"].rolling(50).mean()
        dataframe["volume_mean"] = dataframe["volume"].rolling(30).mean()
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe["atr"] < dataframe["atr_sma"]) &
                (dataframe["close"] > dataframe["close"].rolling(20).max().shift(1)) &
                (dataframe["volume"] > 1.5 * dataframe["volume_mean"])
            ),
            "enter_long",
        ] = 1
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe["close"] < dataframe["close"].rolling(20).min().shift(1))
            ),
            "exit_long",
        ] = 1
        return dataframe
"""


_INTRADAY_REVERSAL_STRATEGY = """from freqtrade.strategy.interface import IStrategy
from pandas import DataFrame
import talib.abstract as ta


class Github_CETANGZHI_flowainew__seed_public_strategies__20260114_114646(IStrategy):
    """30 分钟级别的日内反转策略示例。"""

    minimal_roi = {
        "0": 0.04,
        "60": 0.02,
        "180": 0
    }

    stoploss = -0.08
    timeframe = "30m"

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
        dataframe["prev_close"] = dataframe["close"].shift(1)
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe["close"] < dataframe["prev_close"] * 0.985) &
                (dataframe["rsi"] < 30)
            ),
            "enter_long",
        ] = 1
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe["close"] > dataframe["prev_close"] * 1.01) |
                (dataframe["rsi"] > 55)
            ),
            "exit_long",
        ] = 1
        return dataframe
"""


_MOMENTUM_ROTATION_STRATEGY = """from freqtrade.strategy.interface import IStrategy
from pandas import DataFrame


class Github_CETANGZHI_flowainew__seed_public_strategies__20260114_114646(IStrategy):
    """在多币种之间按动量轮动持仓的简化示例。"""

    minimal_roi = {
        "0": 0.12,
        "1440": 0
    }

    stoploss = -0.15
    timeframe = "1d"

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["return_14"] = dataframe["close"] / dataframe["close"].shift(14) - 1
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                dataframe["return_14"] > 0
            ),
            "enter_long",
        ] = 1
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                dataframe["return_14"] < 0
            ),
            "exit_long",
        ] = 1
        return dataframe
"""


_SIMPLE_GRID_STRATEGY = """from freqtrade.strategy.interface import IStrategy
from pandas import DataFrame


class Github_CETANGZHI_flowainew__seed_public_strategies__20260114_114646(IStrategy):
    """现货网格学习示例（仅供教学使用，未做严谨风控）。"""

    minimal_roi = {
        "0": 0.05,
        "1440": 0
    }

    stoploss = -0.20
    timeframe = "1d"

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["price_sma"] = dataframe["close"].rolling(30).mean()
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe["close"] < dataframe["price_sma"] * 0.97)
            ),
            "enter_long",
        ] = 1
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe["close"] > dataframe["price_sma"] * 1.03)
            ),
            "exit_long",
        ] = 1
        return dataframe
"""


if __name__ == "__main__":  # pragma: no cover
    main()
