-
Notifications
You must be signed in to change notification settings - Fork 724
交易成本模型
交易成本模型是量化回测系统中的关键组成部分,它直接影响策略的收益计算和绩效评估。Hikyuu框架提供了多种内置的交易成本模型,以适应中国A股市场不同历史时期的交易规则。本文档将详细介绍TC_FixedA、TC_FixedA2015、TC_FixedA2017和TC_Zero等内置成本模型的计算逻辑,包括佣金、印花税和过户费的费率与计算方式。同时,本文档将阐述如何通过TradeCostBase接口创建自定义成本模型,指导用户如何将成本模型实例化并配置到TradeManager中,并说明CostRecord如何记录每笔交易产生的费用及其在绩效分析中的作用。
TC_FixedA是Hikyuu框架中用于模拟沪深A股交易成本的基础模型,适用于2015年8月1日之前的市场规则。该模型根据股票的交易所和交易方向,计算不同的交易成本。
计算逻辑:
-
上证交易所 (SH):
- 买入成本 = 佣金 + 过户费
- 卖出成本 = 佣金 + 过户费 + 印花税
-
深证交易所 (SZ):
- 买入成本 = 佣金
- 卖出成本 = 佣金 + 印花税
费率与计算方式:
- 佣金: 按成交金额的千分之1.8(0.0018)计算,但设有最低5元的限制。如果计算出的佣金低于5元,则按5元收取。
- 印花税: 仅在卖出时收取,按成交金额的千分之一(0.001)计算。
- 过户费: 仅对上证交易所的股票收取,按交易数量计算,费率为每股千分之一(0.001)。当交易数量不足1000股时,按最低1元收取;超过1000股时,按实际数量计算。
参数:
-
commission: 佣金比例,默认值为0.0018。 -
lowest_commission: 最低佣金值,默认值为5.0。 -
stamptax: 印花税,默认值为0.001。 -
transferfee: 过户费,默认值为0.001。 -
lowest_transferfee: 最低过户费,默认值为1.0。
示例: 根据测试代码,当以10.0元的价格买入2100股上证股票时,计算过程如下:
- 佣金 = 10.0 * 2100 * 0.0018 = 37.8元
- 过户费 = 2100 * 0.001 = 2.1元
- 总成本 = 37.8 + 2.1 = 39.9元
代码路径:
- TC_FixedA.h
- FixedATradeCost.cpp
Section sources
- TC_FixedA.h
- FixedATradeCost.cpp
TC_FixedA2015模型是TC_FixedA的更新版本,反映了2015年8月1日之后中国A股市场的交易规则变化,特别是上证交易所过户费的调整。
计算逻辑: 该模型的计算规则与TC_FixedA基本相同,主要区别在于过户费的计算方式。
费率与计算方式:
- 过户费: 不再按交易数量计算,而是改为按成交金额的万分之二(0.00002)计算。这一变化使得过户费与交易金额直接挂钩,而非交易股数。
参数:
-
commission: 佣金比例,默认值为0.0018。 -
lowest_commission: 最低佣金值,默认值为5.0。 -
stamptax: 印花税,默认值为0.001。 -
transferfee: 过户费,默认值为0.00002。
示例: 当以10.0元的价格买入2100股上证股票时,计算过程如下:
- 佣金 = 10.0 * 2100 * 0.0018 = 37.8元
- 过户费 = 10.0 * 2100 * 0.00002 = 4.2元
- 总成本 = 37.8 + 4.2 = 42.0元
代码路径:
- TC_FixedA2015.h
- FixedA2015TradeCost.cpp
Section sources
- TC_FixedA2015.h
- FixedA2015TradeCost.cpp
TC_FixedA2017模型进一步更新了交易规则,以适应2017年1月1日之后的市场变化。最大的变化是深市也开始收取过户费。
计算逻辑:
-
上证交易所 (SH):
- 买入成本 = 佣金 + 过户费
- 卖出成本 = 佣金 + 过户费 + 印花税
-
深证交易所 (SZ):
- 买入成本 = 佣金 + 过户费
- 卖出成本 = 佣金 + 过户费 + 印花税
费率与计算方式:
- 过户费: 统一按成交金额的万分之二(0.00002)双向收取,适用于所有A股股票,无论其在上证还是深证交易所上市。
参数:
-
commission: 佣金比例,默认值为0.0018。 -
lowest_commission: 最低佣金值,默认值为5.0。 -
stamptax: 印花税,默认值为0.001。 -
transferfee: 过户费,默认值为0.00002。
示例: 当以10.0元的价格买入2100股深证股票时,计算过程如下:
- 佣金 = 10.0 * 2100 * 0.0018 = 37.8元
- 过户费 = 10.0 * 2100 * 0.00002 = 4.2元
- 总成本 = 37.8 + 4.2 = 42.0元
代码路径:
- TC_FixedA2017.h
- FixedA2017TradeCost.cpp
Section sources
- TC_FixedA2017.h
- FixedA2017TradeCost.cpp
TC_Zero是一个特殊的成本模型,它将所有交易成本设置为零。这个模型主要用于理论分析或在不考虑交易成本影响的情况下进行策略的初步测试。
计算逻辑: 无论进行何种交易操作(买入或卖出),该模型返回的CostRecord中所有费用(佣金、印花税、过户费、其他费用和总成本)均为0。
用途:
- 作为基准模型,用于评估交易成本对策略收益的实际影响。
- 在策略开发的早期阶段,快速验证策略逻辑的正确性,而不受交易成本的干扰。
代码路径:
- TC_Zero.h
- ZeroTradeCost.cpp
Section sources
- TC_Zero.h
- ZeroTradeCost.cpp
Hikyuu框架通过TradeCostBase抽象基类提供了创建自定义成本模型的接口。用户可以通过继承TradeCostBase类并实现其纯虚函数来定义符合特定需求的交易成本计算逻辑。
接口定义:
TradeCostBase类定义了两个必须实现的纯虚函数:
-
getBuyCost(const Datetime& datetime, const Stock& stock, price_t price, double num) const: 计算买入指定股票的成本。 -
getSellCost(const Datetime& datetime, const Stock& stock, price_t price, double num) const: 计算卖出指定股票的成本。
此外,继承类还必须实现_clone()虚函数,用于创建自身的一个副本。
创建步骤:
- 创建一个新类,继承自
TradeCostBase。 - 在构造函数中,通过
setParam()方法设置模型的参数,并调用基类构造函数指定模型名称。 - 实现
getBuyCost和getSellCost函数,根据业务逻辑计算各项费用。 - 实现
_clone()函数,返回一个指向新创建对象的智能指针。 - (可选)重写
_checkParam()函数,对参数的有效性进行校验。
Python示例: 在Python中,可以更方便地创建自定义成本模型。以下是一个简单的示例:
class PythonTradeCost(TradeCostBase):
def __init__(self):
super(PythonTradeCost, self).__init__("PythonTradeCost")
def get_sell_cost(self, date, stock, price, num):
return CostRecord(2.0, 2.0, 2.0, 2.0, 8.0)
def _clone(self):
return PythonTradeCost()此示例创建了一个名为"PythonTradeCost"的模型,其卖出成本固定为8元(佣金2元、印花税2元、过户费2元、其他费用2元)。
代码路径:
- TradeCostBase.h
- TradeCost.py
Section sources
- TradeCostBase.h
- TradeCost.py
在Hikyuu框架中,交易成本模型需要被实例化并配置到TradeManager(交易管理器)中,才能在回测过程中生效。
实例化: Hikyuu提供了多个全局函数来快速创建内置成本模型的实例:
-
TC_FixedA(): 创建TC_FixedA模型实例。 -
TC_FixedA2015(): 创建TC_FixedA2015模型实例。 -
TC_FixedA2017(): 创建TC_FixedA2017模型实例。 -
TC_Zero(): 创建TC_Zero模型实例。
这些函数可以接受参数来覆盖默认的费率设置。例如,TC_FixedA2017(0.0015, 3.0)将创建一个佣金比例为千分之1.5、最低佣金为3元的TC_FixedA2017模型。
配置到TradeManager:
TradeManager的构造函数接受一个TradeCostPtr类型的参数,用于指定回测所使用的成本模型。如果未指定,将默认使用TC_Zero()。
// 创建一个使用TC_FixedA2017成本模型的交易管理器
TradeManager tm(Datetime(202001010000), 100000.0, TC_FixedA2017());参数调整:
对于已创建的成本模型实例,可以使用setParam()和getParam()方法动态调整和查询参数。例如:
auto tc = TC_FixedA2017();
tc.setParam("commission", 0.001);
double currentCommission = tc.getParam<price_t>("commission");代码路径:
- TradeManager.h
- TC_FixedA.h
- TC_FixedA2015.h
- TC_FixedA2017.h
- TC_Zero.h
Section sources
- TradeManager.h
- TC_FixedA.h
- TC_FixedA2015.h
- TC_FixedA2017.h
- TC_Zero.h
CostRecord结构体是Hikyuu框架中用于记录单笔交易所有成本信息的核心数据结构。
数据结构:
CostRecord包含以下五个成员变量:
-
commission: 佣金 -
stamptax: 印花税 -
transferfee: 过户费 -
others: 其他费用 -
total: 总成本
记录过程:
每当TradeManager执行一次买入或卖出操作时,它会调用当前配置的TradeCostBase实例的getBuyCost或getSellCost方法。该方法返回一个CostRecord对象,TradeManager会将此对象作为TradeRecord(交易记录)的一部分进行存储。
在绩效分析中的作用: 精确的成本记录对于绩效分析至关重要:
- 准确计算收益: 交易成本直接从投资收益中扣除。不准确的成本模型会导致收益被高估或低估。
- 策略比较: 通过对比使用不同成本模型的回测结果,可以量化交易成本对策略表现的影响。
- 风险评估: 高频交易策略对交易成本极为敏感。精确的成本模型有助于评估策略在真实市场环境下的可行性。
- 参数优化: 成本模型的参数(如佣金率)可以作为策略优化的一部分,以找到在特定成本结构下的最优参数。
代码路径:
- CostRecord.h
- TradeManager.h
Section sources
- CostRecord.h
- TradeManager.h
为了说明不同成本模型对回测结果的影响,我们可以设想一个简单的回测场景。
场景设定:
- 初始资金:100,000元
- 策略:简单的双均线策略,交易标的为上证50指数成分股
- 回测周期:2016年1月1日至2016年12月31日
- 交易频率:中等,平均每月交易20次
预期结果对比:
- 使用TC_Zero模型: 回测结果将显示最高的收益率,因为它忽略了所有交易成本。这个结果可以看作是策略的“理论最大收益”。
- 使用TC_FixedA2015模型: 由于2016年处于该模型适用的时期,此结果最接近真实情况。收益率将显著低于TC_Zero的结果,差额主要由佣金、印花税和过户费构成。
- 使用TC_FixedA模型: 此模型低估了过户费(按股数而非成交金额计算),因此其计算出的总成本会低于实际成本,导致回测收益率被高估。
- 使用TC_FixedA2017模型: 虽然2016年深市尚未收取过户费,但此模型会错误地对深市股票收取过户费,从而略微高估了总成本,导致回测收益率被低估。
通过这种对比,用户可以清晰地认识到选择正确成本模型的重要性,以及交易成本对策略盈利能力的巨大影响。
Hikyuu框架提供了灵活且功能强大的交易成本模型系统。从TC_FixedA到TC_FixedA2017,这些内置模型精确地反映了中国A股市场在不同历史时期的交易规则变迁。TC_Zero模型则为理论分析提供了便利。通过TradeCostBase接口,用户可以轻松创建自定义模型以适应特殊需求。将成本模型正确配置到TradeManager中,并通过CostRecord精确记录每笔交易的成本,是进行可靠回测和绩效分析的基础。选择与回测周期相匹配的成本模型,对于获得真实、可信的策略评估结果至关重要。