这个咋样hhhhhhhhh

用户头像sh_*81368q
2026-09-11 发布

-- coding:utf-8 --

import pandas as pd
import numpy as np

===================== 参数 =====================

MA_SHORT = 5 # 日线短均线周期
MA_LONG = 13 # 日线/月线长均线周期
STOP_LOSS = 0.08 # 止损线:8%
MAX_HOLD_DAYS = 20 # 最长持仓天数
DROP_FROM_HIGH = 0.07 # 从最高点回落7%卖出
SINGLE_DAY_DROP = 0.05 # 单日跌幅5%卖出

=================================================

def init(context):
set_benchmark('000300.SH')
log.info('=== 月线区间(5月金叉~收盘价死叉) + 日线5/13策略 ===')
log.info('月线金叉: 5月均线上穿13月均线')
log.info('月线死叉: 月线收盘价下穿13月均线')
log.info('买入: 月线多头区间内 + 日线5上穿13')
log.info('卖出: 日线5下穿13 / 月线死叉 / 高位急跌 / 止损 / 持仓超时')

set_commission(PerShare(type='stock', cost=0.0002))
set_slippage(PriceSlippage(0.005))
set_volume_limit(0.25, 0.5)

context.security = [
"600000.SH","600004.SH","600009.SH","600010.SH","600015.SH",
"600016.SH","600018.SH","600019.SH","600028.SH","600029.SH",
"600030.SH","600031.SH","600036.SH","600048.SH","600050.SH",
"600104.SH","600111.SH","600276.SH","600309.SH","600519.SH",
"600585.SH","600887.SH","600900.SH","601318.SH","601398.SH",
"601857.SH","601988.SH","000001.SZ","000002.SZ","000333.SZ",
"000651.SZ","000858.SZ","000725.SZ","000063.SZ","000100.SZ"
]

context.position = 0
context.buy_stock = None
context.buy_price = 0
context.hold_days = 0
context.highest_price = 0
def before_trading(context):
date = get_datetime().strftime('%Y-%m-%d %H:%M:%S')
if context.position == 1:
log.info('{} 盘前, 持仓:{} 买入价:%.2f 最高价:%.2f 已持%d天'.format(
date, context.buy_stock, context.buy_price,
context.highest_price, context.hold_days))
else:
log.info('{} 盘前, 空仓'.format(date))

def handle_bar(context, bar_dict):
time = get_datetime().strftime('%Y-%m-%d %H:%M:%S')

stock_account = context.portfolio.stock_account
has_position = len(stock_account.positions) > 0

===================== 1. 卖出逻辑 =====================

if has_position:
context.hold_days += 1
stock = list(stock_account.positions.keys())[0]
current_price = bar_dict[stock].close

if current_price > context.highest_price:
    context.highest_price = current_price

sell, reason = check_sell_signal(context, stock, current_price)

if sell:
    profit = (current_price / context.buy_price - 1) * 100 if context.buy_price > 0 else 0
    log.info('='*50)
    log.info('🔻 [%s] 卖出 %s' % (time, stock))
    log.info('   原因: %s' % reason)
    log.info('   买入价: %.2f, 现价: %.2f, 收益: %.2f%%' % (
        context.buy_price, current_price, profit))
    log.info('='*50)
    order_target(stock, 0)
    context.position = 0
    context.buy_stock = None
    context.buy_price = 0
    context.hold_days = 0
    context.highest_price = 0
return

===================== 2. 买入逻辑 =====================

buy_stock = check_buy_signal(context, bar_dict)

if buy_stock is not None:
current_price = bar_dict[buy_stock].close
log.info('='*50)
log.info('📈 [%s] 买入 %s' % (time, buy_stock))
log.info(' 价格: %.2f' % current_price)
log.info('='*50)
order_target_percent(buy_stock, 1)
context.position = 1
context.buy_stock = buy_stock
context.buy_price = current_price
context.hold_days = 0
context.highest_price = current_price
def check_sell_signal(context, stock, current_price):
"""卖出判断"""

---------- 条件1:高位急跌 ----------

if context.highest_price > 0:
drop_from_high = (current_price / context.highest_price - 1)
if drop_from_high <= -DROP_FROM_HIGH:
return True, '高位回落%.2f%%' % (drop_from_high * 100)

daily_data = history(stock, ['close'], 400, '1d', False, 'pre')
if daily_data is None or len(daily_data) < 30:
return False, ''

close_arr = daily_data['close'].values

单日急跌

if len(close_arr) >= 2:
prev_close = close_arr[-2]
if prev_close > 0:
day_drop = (current_price / prev_close - 1)
if day_drop <= -SINGLE_DAY_DROP:
return True, '单日急跌%.2f%%' % (day_drop * 100)

---------- 条件2:止损 ----------

if context.buy_price > 0:
loss = (current_price / context.buy_price - 1)
if loss <= -STOP_LOSS:
return True, '止损 (亏损%.2f%%)' % (loss * 100)

---------- 条件3:持仓超时 ----------

if context.hold_days >= MAX_HOLD_DAYS:
return True, '持仓超过%d天' % MAX_HOLD_DAYS

df = pd.DataFrame({
'close': close_arr
}, index=pd.to_datetime(daily_data.index))

---------- 条件4:月线死叉(收盘价下穿13月均线)----------

monthly_df = df.resample('M').agg({'close': 'last'}).dropna()
if len(monthly_df) >= MA_LONG + 5:
monthly_close = monthly_df['close'].values
m_ma_long = pd.Series(monthly_close).rolling(MA_LONG).mean().values

# 月线收盘价 < 13月均线 → 月线死叉(区间结束)
if monthly_close[-1] < m_ma_long[-1]:
    return True, '月线死叉(收盘价<13月均线)'

---------- 条件5:日线5下穿13 ----------

d_ma_short = pd.Series(close_arr).rolling(MA_SHORT).mean().values
d_ma_long = pd.Series(close_arr).rolling(MA_LONG).mean().values

d_short_cur = d_ma_short[-1]
d_long_cur = d_ma_long[-1]
d_short_prev = d_ma_short[-2]
d_long_prev = d_ma_long[-2]

daily_dead = (d_short_prev >= d_long_prev) and (d_short_cur < d_long_cur)

if daily_dead:
return True, '日线5下穿13'

return False, ''
def check_buy_signal(context, bar_dict):
"""买入判断:月线区间(5月金叉~收盘价死叉) + 日线5上穿13"""
for stock in context.security:
daily_data = history(stock, ['close'], 400, '1d', False, 'pre')
if daily_data is None or len(daily_data) < 100:
continue

df = pd.DataFrame({
    'close': daily_data['close'].values
}, index=pd.to_datetime(daily_data.index))

# ===== 月线方向 =====
monthly_df = df.resample('M').agg({'close': 'last'}).dropna()
if len(monthly_df) < MA_LONG + 5:
    continue

monthly_close = monthly_df['close'].values
m_ma_short = pd.Series(monthly_close).rolling(MA_SHORT).mean().values
m_ma_long  = pd.Series(monthly_close).rolling(MA_LONG).mean().values

# 找最近一次"金叉"和"死叉"的位置
# 金叉:5月均线上穿13月均线
# 死叉:月线收盘价下穿13月均线

month_gold_idx = -1
month_dead_idx = -1

for i in range(1, len(monthly_close)):
    # 金叉:5月均线上穿13月均线
    if (m_ma_short[i-1] <= m_ma_long[i-1] and 
        m_ma_short[i] > m_ma_long[i]):
        month_gold_idx = i
  
    # 死叉:月线收盘价下穿13月均线
    if (monthly_close[i-1] >= m_ma_long[i-1] and 
        monthly_close[i] < m_ma_long[i]):
        month_dead_idx = i

# 判断当前是否在"金叉之后、死叉之前"的区间
if month_gold_idx <= month_dead_idx:
    continue  # 不在多头区间

# ===== 日线金叉 =====
daily_close = df['close'].values
d_ma_short = pd.Series(daily_close).rolling(MA_SHORT).mean().values
d_ma_long  = pd.Series(daily_close).rolling(MA_LONG).mean().values

d_short_cur  = d_ma_short[-1]
d_long_cur   = d_ma_long[-1]
d_short_prev = d_ma_short[-2]
d_long_prev  = d_ma_long[-2]

daily_gold = (d_short_prev <= d_long_prev) and (d_short_cur > d_long_cur)

if daily_gold:
    log.info('   ✅ %s 月线区间内(5月金叉~收盘价死叉) + 日线5上穿13' % stock)
    return stock

return None
def after_trading(context):
time = get_datetime().strftime('%Y-%m-%d %H:%M:%S')
pos_list = list(context.portfolio.stock_account.positions)
if len(pos_list) > 0:
log.info('{} 盘后, 持仓:{}, 市值:{:.2f}'.format(
time, pos_list, context.portfolio.stock_account.total_value))
else:
log.info('{} 盘后, 空仓'.format(time))

评论