金字塔决策交易系统

 找回密码
 

微信登录

微信扫一扫,快速登录

搜索
查看: 396|回复: 12

python回测的明细怎么看,为什么怎么算好像都不太对

[复制链接]

1

主题

7

帖子

7

积分

Rank: 1

等级: 新手上路

注册:
2025-7-8
曾用名:
发表于 2025-7-8 22:17 | 显示全部楼层 |阅读模式

回测系统中:盈利不等于股票差价*股票数量-手续费吗????
截图202507082216321298.png
回复

使用道具 举报

3

主题

811

帖子

852

积分

Rank: 9Rank: 9Rank: 9

等级: 管理员

注册:
2021-5-10
曾用名:
发表于 2025-7-9 08:29 | 显示全部楼层
是的,不一样的原因是因为显示的平仓价和开仓价是经过四舍五入整理后显示的价格。实际计算机是按照浮点型的原始数据进行的计算,例如显示的21.90 实际可能是21.9019。最终计算得到的累计盈亏和手工验算的存在误差。
回复

使用道具 举报

1

主题

7

帖子

7

积分

Rank: 1

等级: 新手上路

注册:
2025-7-8
曾用名:
 楼主| 发表于 2025-7-9 09:04 | 显示全部楼层
那为什么我设置用开盘价买入,回测显示还是收盘价?是回测系统的问题?
回复

使用道具 举报

0

主题

1万

帖子

1万

积分

Rank: 8Rank: 8

等级: 超级版主

注册:
2021-5-18
曾用名:
gxx978
发表于 2025-7-9 09:13 | 显示全部楼层
入场的价格是和你代码中的报单指令有关啊。你是如何设置的呢?你回测的是旧图表交易系统?是在入场规则中指定的?
金字塔提供一对一VIP专业技术指导服务,技术团队实时响应您的日常使用问题与策略编写。联系电话:021-20339086
回复

使用道具 举报

1

主题

7

帖子

7

积分

Rank: 1

等级: 新手上路

注册:
2025-7-8
曾用名:
 楼主| 发表于 2025-7-9 09:24 | 显示全部楼层
技术010 发表于 2025-7-9 09:13
入场的价格是和你代码中的报单指令有关啊。你是如何设置的呢?你回测的是旧图表交易系统?是在入场规则中指 ...

是的呀,我代码写入的价格是开盘价,信息窗口显示的买入价格也是开盘价,一到回测系统中就显示为收盘价;因为统计指标会有所不同(使用开盘、收盘不同),所以我怀疑是不是回测系统的显示问题
回复

使用道具 举报

0

主题

1万

帖子

1万

积分

Rank: 8Rank: 8

等级: 超级版主

注册:
2021-5-18
曾用名:
gxx978
发表于 2025-7-9 09:26 | 显示全部楼层
你是代码中指定的报单价格?那把你的开仓语句代码发来看下呢。我们测试下
金字塔提供一对一VIP专业技术指导服务,技术团队实时响应您的日常使用问题与策略编写。联系电话:021-20339086
回复

使用道具 举报

1

主题

7

帖子

7

积分

Rank: 1

等级: 新手上路

注册:
2025-7-8
曾用名:
 楼主| 发表于 2025-7-9 09:29 | 显示全部楼层
技术010 发表于 2025-7-9 09:26
你是代码中指定的报单价格?那把你的开仓语句代码发来看下呢。我们测试下

buy_price = get_price(stock)  # 获取开盘价
print(buy_price)
buy_open(stock, 'Market', buy_price, volume,serial_id = 2)
context.positions[stock] = {'buy_price': price, 'volume': volume}
built_count += 1
print(f"成功建仓 {stock},价格 {price:.2f},数量 {volume}")

def get_price(stock):
    bars = history_bars(stock, 1, '1d', ['OPEN'], skip_suspended=True, include_now=False)
    if not bars or len(bars) == 0:
        return None
    #print(bars[-1])
    return bars[-1]  # 确保获取的是当天的开盘价
回复

使用道具 举报

1

主题

7

帖子

7

积分

Rank: 1

等级: 新手上路

注册:
2025-7-8
曾用名:
 楼主| 发表于 2025-7-9 09:31 | 显示全部楼层
import datetime
import pandas as pd

def init(context):
    context.strategy_capital = 100_000
    context.positions = {}
    context.pending_sell_orders = {}
    context.already_bought = False
    context.trading_day_count = 0
    context.MAX_ATTEMPTS = 5
    context.TARGET_BUY_COUNT = 5
    context.rate=1.05
    df = pd.read_csv("D:/tushare/analyse_data/result/final_top20_combined_score_2025-06-27.csv", dtype=str)
    df['code'] = df['code'].astype(str).str.strip().str.upper()
    context.target_stocks = df['code'].tolist()
   
def handle_bar(context):
    if context.trading_day_count > 3:
        return  # 限制最多运行3个交易日

    # Step 0: 处理未完成追单
    for stock in list(context.pending_sell_orders.keys()):
        price = get_price(stock)
        volume = context.pending_sell_orders[stock]['volume']
        attempts = context.pending_sell_orders[stock]['attempts']

        if price is None or price <= 0:
            context.pending_sell_orders[stock]['attempts'] += 1
            if attempts + 1 >= context.MAX_ATTEMPTS:
                print(f"{stock} 清仓失败超过最大次数,放弃追单")
                del context.pending_sell_orders[stock]
            continue

        # 卖出时使用开盘价
        sell_price = get_price(stock)  # 获取开盘价
        sell_close(stock, 'Limit', sell_price, volume,serial_id = 1)
        print(f"{stock} 第 {attempts + 1} 次追单挂出")
        del context.pending_sell_orders[stock]

    # Step 1: 第1个交易日建仓(支持涨停候补)
    if context.trading_day_count == 1 and not context.already_bought:
        cash_per_stock = context.strategy_capital / context.TARGET_BUY_COUNT
        built_count = 0
        candidate_stocks = []

        for stock in context.target_stocks:
            if built_count >= context.TARGET_BUY_COUNT:
                break

            price = get_price(stock)
            if price is None or price <= 0:
                print(f"{stock} 无法获取价格,加入候补池")
                candidate_stocks.append(stock)
                continue

            volume = int(cash_per_stock / price // 100) * 100
            if volume < 100:
                print(f"{stock} 成交量不足 100 股,加入候补池")
                candidate_stocks.append(stock)
                continue
            
            turnover_rate = get_turnover_rate(stock, 1, 5)
            #print(turnover_rate[-1].values)
            if turnover_rate[-1].values is None or turnover_rate[-1].values < 0.01:
                print(f"{stock} 换手率过低,跳过")
                continue
            buy_price = get_price(stock)  # 获取开盘价
            print(buy_price)
            buy_open(stock, 'Market', buy_price, volume,serial_id = 2)
            context.positions[stock] = {'buy_price': price, 'volume': volume}
            built_count += 1
            print(f"成功建仓 {stock},价格 {price:.2f},数量 {volume}")

        # 候补建仓
        for stock in candidate_stocks:
            if built_count >= context.TARGET_BUY_COUNT:
                break

            price = get_price(stock)
            if price is None or price <= 0:
                continue

            volume = int(cash_per_stock / price // 100) * 100
            if volume < 100:
                continue
            buy_price = get_price(stock)  # 获取开盘
            buy_open(stock, 'Market', buy_price, volume,serial_id = 3)
            context.positions[stock] = {'buy_price': price, 'volume': volume}
            built_count += 1
            print(f"候补建仓成功:{stock},价格 {price:.2f},数量 {volume}")

        context.already_bought = True
        print(f"第1个交易日建仓完成,共建仓 {built_count} 只股票")

    # Step 2: 第2个交易日止盈止损
    elif context.trading_day_count == 2:
        for stock in list(context.positions.keys()):
            price = get_price(stock)
            if price is None or price <= 0:
                context.pending_sell_orders[stock] = {
                    'volume': context.positions[stock]['volume'],
                    'attempts': 1
                }
                print(f"{stock} 无法获取价格,加入追单池")
                continue
            
            buy_price = context.positions[stock]['buy_price']
            volume = context.positions[stock]['volume']
            if price >= buy_price * context.rate or price <= buy_price * 0.95:
                # 卖出时使用开盘价
                sell_price = get_price(stock)  # 获取开盘价
                print(sell_price)
                sell_close(stock, 'Market', sell_price, volume,serial_id = 4)
                print(f"{stock} 触发止盈/止损,卖出")
                del context.positions[stock]

    # Step 3: 第3个交易日强制清仓
    elif context.trading_day_count == 3:
        for stock in list(context.positions.keys()):
            price = get_price(stock)
            volume = context.positions[stock]['volume']
            if price is None or price <= 0:
                context.pending_sell_orders[stock] = {'volume': volume, 'attempts': 1}
                print(f"{stock} 第3日仍无法获取价格,加入追单池")
                continue

            # 卖出时使用开盘价
            sell_price = get_price(stock)  # 获取开盘价
            print(sell_price)
            sell_close(stock, 'Market', sell_price, volume,serial_id = 5)
            print(f"{stock} 第3日强制清仓完成")
            del context.positions[stock]

    context.trading_day_count += 1
   
def get_price(stock):
    bars = history_bars(stock, 1, '1d', ['OPEN'], skip_suspended=True, include_now=False)
    if not bars or len(bars) == 0:
        return None
    #print(bars[-1])
    return bars[-1]  # 确保获取的是当天的开盘价
回复

使用道具 举报

0

主题

1万

帖子

1万

积分

Rank: 8Rank: 8

等级: 超级版主

注册:
2021-5-18
曾用名:
gxx978
发表于 2025-7-9 09:34 | 显示全部楼层
那是因为你的报单语句中用的是market指令啊,如果你要指定价格报单,那要用limit指令
截图202507090934539197.png
金字塔提供一对一VIP专业技术指导服务,技术团队实时响应您的日常使用问题与策略编写。联系电话:021-20339086
回复

使用道具 举报

1

主题

7

帖子

7

积分

Rank: 1

等级: 新手上路

注册:
2025-7-8
曾用名:
 楼主| 发表于 2025-7-9 09:38 | 显示全部楼层
技术010 发表于 2025-7-9 09:13
入场的价格是和你代码中的报单指令有关啊。你是如何设置的呢?你回测的是旧图表交易系统?是在入场规则中指 ...

还是说回测不能用history_bar,直接用get_dynainf
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 微信登录

本版积分规则

手机版|小黑屋|上海金之塔信息技术有限公司 ( 沪ICP备13035422号 )

GMT+8, 2025-7-16 02:24 , Processed in 0.128927 second(s), 24 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表