我们现在已经可以在主循环中获取行情数据,并且传给了Agent类。接下来Agent类会调用策略类,由于决定采取的行动。在策略类做决策时,需要参考用户仓位Position信息,还有就是权利金、保证金、手续费等计算,在本篇博文中将对这些内容进行介绍。
在进行期权交易时,多头买入认购和认沽期权时,需要向卖出方支付权利金,而为了保证卖方可以履约,要向卖方收取保证金。同时,券商还会收取手续费和税费,手续费和税费可能单边收取也可能双边收取,情况比较复杂。因此我们采用Commission类来进行管理。
我们首先来定义费用类和权利金的计算方法:
class Commission(object):
def __init__(self):
self.refl = 'apps.sop.exchange.Commission'
def calculate_royalty(self, price, quant):
'''
计算期权交易的权利金,权利金直接由买方转给卖方
参数:
price 合约价格
quant 多少手,1手为10000份
'''
return price * quant * SopConfig.contract_unit
# 单元测试用例类定义
class TCommission(unittest.TestCase):
@classmethod
def setUp(cls):
pass
@classmethod
def tearDown(cls):
pass
def test_calculate_royalty(self):
cmn = Commission()
royalty = cmn.calculate_royalty(0.1, 28)
self.assertTrue(abs(royalty - 28000))
# 运行方法
python -m unittest uts.apps.sop.exchange.t_commission.TCommission.test_calculate_royalty -v
接下来我们来计算卖家需要预缴的保证金。根据我国证券市场的规定,认购期权和认沽期权卖方需要支付不同的保证金。下面分别对认购期权和认沽期权,以单位交易的保证金为例进行介绍。
当为认购期权时,按照以下值的较大者为准收取:
公式1:
v 1 = p × u + p a s s e t × u × r − ( p a s s e t − e ) × u v_1 = p \times u + p_{asset} \times u \times r - (p_{asset} - e) \times u v1=p×u+passet×u×r−(passet−e)×u
其中:
公式2:
v 2 = p × u + p a s s e t × u × r v_2 = p \times u + p_{asset} \times u \times r v2=p×u+passet×u×r
目前规定取金额1和金额2中间的较小值。
当为认沽期权时:
金额1定义:
v 1 = p × u + p a s s e t × u × r − ( e − p a s s e t ) × u v_1 = p \times u + p_{asset} \times u \times r - (e -p_{asset}) \times u v1=p×u+passet×u×r−(e−passet)×u
金额2定义:
v 2 = p × u + p a s s e t × u × r v_2 = p \times u + p_{asset} \times u \times r v2=p×u+passet×u×r
最终价格取v1和v2中的较小值。
我们用Position类来表示用户的仓位,包括用户的现金金额、持有的认购合约编号和数量列表、持有的认沽期权合约编号和数量列表,同时还有净值金额,其为现金金额再加上持有的期权合约在当前市场价格下的金额。
Position类定义如下所示:
class Position(object):
def __init__(self):
self.name = 'apps.sop.exchange.Position'
self.amount = 0.0 # 现金账户
self.net_worth = 0.0 # 净值
self.call_options = [] # 持有的认购合约列表
self.put_options = [] # 持有的认沽合约列表
self.rpnl = 0.0 # 已实现损益
self.upnl = 0.0 # 未实现损益
接下来我们来看策略类,我们在这里先不讲具体的策略,这里先只产生买入操作,主要目的是先将期权交易的整体流程走通,然后我们再来逐一细化回测平台的各个组件。
所有策略类都有一个基类Strategy,其有一个run方法,就是看到环境的状态obs和上一时刻行动的奖励信号reward,然后生成一个action。我们会在Agent类的choose_action方法中对其进行调用。
在实际应用系统中,我们会定义多个Strategy类的子类,同时还会定义一些组合策略。
策略基类Strategy定义如下所示:
class BaseStrategy(object):
def __init__(self, action):
self.refl = 'apps.sop.snp.BaseStragegy'
self.action = action
def run(self, obs, reward):
self.action.reset()
option_idx = 0
self.action.action[SopAction.IDX_OPTION][option_idx] = 1
action_idx = 0
self.action.action[SopAction.IDX_ACTION][action_idx] = 1
percent_idx = 9
self.action.action[SopAction.IDX_PERCENT][percent_idx] = 1
return self.action.action
def reset(self):
self.action.reset()
在实际系统中,策略类做出决策后,需要调用风险控制模块进行审核,当通过风控模块审核后,才能进行真实交易。
风险控制类定义如下所示:
class RiskController(object):
def __init__(self):
self.refl = 'apps.sop.snp.RiskController'
def review_action(self, obs, reward, action):
'''
验证当前状态obs下采取action的合理性
返回值:True同意,False拒绝
'''
print('风控审核通过!!!!!!!!!!!!!!!!!!')
return True
在Agent类的choose_action中,当调用Strategy.run方法生成action后,将调用RiskController.review_action方法,审核通过返回True,不通过返回False,如下所示:
class SopAgent(object):
def choose_action(self, obs, reward):
'''
根据环境当前状态选择本时间点的行动,将上一时间点行动的奖励信号
用于策略学习
'''
print('看到:{0};\n奖励:{1};'.format(obs, reward))
action = self.strategy.run(obs, reward)
if not self.risk_controller.review_action(obs, reward, action):
action.reset()
return action
当审核通过后,Agent将所选择的行动发送给环境类SopEnv,其会调用_execute_action来执行该行动,这里是生成订单Order,并调用Broker类来执行。
我们先来定义订单Order类:
class Order(object):
def __init__(self, action):
self.refl = 'apps.sop.exchange.Order'
def __str__(self):
msg = '订单类:'
return msg
在环境类SopEnv._execute_action中生成订单,如下所示:
def _execute_action(self, action):
order = Order(action)
print('执行订单:{0};'.format(order))
接下来我们定义券商Broker类,在该类中将计算和转移权利金、保证金、交易手续费和税费,并最终向证券交易所系统提交并执行订单,如下所示:
class Broker(object):
def __init__(self):
self.refl = 'apps.sop.exchange.Broker'
def execute_order(self, order):
print('券商系统订单执行完毕')
在环境类SopEnv._execute_action方法调用:
def _execute_action(self, action):
order = Order(action)
self.broker.execute_order(order)
至此我们已经引入了强化学习回测系统中所有的基础类,总结一下总体的业务流程: