我正在构建一个交易机器人,并且我正在尝试实施一个优化器以在遵守某些约束的同时最大化 alpha。
我的变量是一个包含投资组合中证券权重的向量。我还有一个向量,其中包含每种证券各自的 alpha 分数。我的目标函数是 -sum(weights*alphas) (以最小化负 alpha)。我的限制是:
- 投资组合中股票的最小和最大权重
- 最低交易量(占投资组合总价值的百分比 - 交易成本是固定的,所以如果只是几个基点变化,我不想交易)
- 最大营业额(最大总交易价值占投资组合总价值的百分比)
- 绝对权重之和必须为 1
- 权重之和必须等于 0(长/短)或 1(仅长)
我在下面创建了一个类,它使用 scipy.optimize.minimize 来实现它:
class Optimiser:
def __init__(self, initial_portfolio, turnover, min_trade, max_wt, longshort=True):
self.symbols = initial_portfolio.index.to_numpy()
self.init_wt = initial_portfolio['weight'].to_numpy()
self.alpha = initial_portfolio['alpha'].to_numpy()
self.longshort = longshort
self.turnover = turnover
self.min_trade = self.init_wt.copy()
self.set_min_trade(min_trade)
self.max_wt = max_wt
if self.longshort:
self.wt_sum = 0
self.abs_wt_sum = 1
else:
self.wt_sum = 1
self.abs_wt_sum = 1
def set_min_trade(self, min_trade):
for i in range(len(self.init_wt)):
if abs(self.init_wt[i]) > min_trade:
self.min_trade[i] = 0.1
def optimise(self):
wt_bounds = self.get_stock_wt_bounds()
constraints = self.get_constraints()
result = minimize(
fun=self.minimise_negative_alpha,
x0=self.init_wt,
bounds=wt_bounds,
constraints=constraints,
options={
'disp': True,
}
)
return result
def minimise_negative_alpha(self, opt_wt):
return -sum(opt_wt * self.alpha)
def get_stock_wt_bounds(self):
if self.longshort:
return tuple((-self.max_wt, self.max_wt) for s in self.init_wt)
else:
return tuple((0, self.max_wt) for i in range(len(self.init_wt)))
def get_constraints(self):
min_trade = {'type': 'ineq', 'fun': self.min_trade_fn}
turnover = {'type': 'ineq', 'fun': self.turnover_fn}
wt_sum = {'type': 'eq', 'fun': self.wt_sum_fn}
abs_wt_sum = {'type': 'eq', 'fun': self.abs_wt_sum_fn}
return turnover, wt_sum, abs_wt_sum
def min_trade_fn(self, opt_wt):
return self.min_trade - abs(opt_wt - self.init_wt)
def turnover_fn(self, opt_wt):
return sum(abs(opt_wt - self.init_wt)) - self.turnover*2
def wt_sum_fn(self, opt_wt):
return sum(opt_wt)
def abs_wt_sum_fn(self, opt_wt):
return sum(abs(opt_wt)) - self.abs_wt_sum
如您所见,我没有使用 min_trade 约束,稍后我将在问题中涉及到这一点。
这是我传递给它的两个示例(这些示例仅包含 4 只股票,并且在正确的实现中,我希望传递 50-100 证券的数组):
一种)
def run_optimisation():
initial_portfolio = pd.DataFrame({
'symbol': ['AAPL', 'MSFT', 'GOOGL', 'TSLA'],
'weight': [-0.3, -0.2, 0.45, 0.05],
'alpha': [-0.2, -0.3, 0.25, 0],
}).set_index('symbol')
opt = Optimiser(initial_portfolio, turnover=0.3, min_trade=0.1, max_wt=0.4)
result = opt.optimise()
b)
def run_optimisation():
initial_portfolio = pd.DataFrame({
'symbol': ['AAPL', 'MSFT', 'GOOGL', 'TSLA'],
'weight': [-0.25, -0.25, 0.25, 0.25],
'alpha': [-0.2, -0.3, 0.25, 0],
}).set_index('symbol')
opt = Optimiser(initial_portfolio, turnover=0.3, min_trade=0.1, max_wt=0.4)
result = opt.optimise()
对于这个长短示例,我从 a) 得到的结果是:[-0.1, -0.4, 0.25, 0.25],这显然不是最优的 [-0.1, -0.4, 0.4, 0.1]。
我收到这条消息:
Optimization terminated successfully. (Exit mode 0)
Current function value: -0.20249999999999585
Iterations: 7
Function evaluations: 42
Gradient evaluations: 7
它说它成功地找到了最小值......这就像它试图最大化营业额约束。这是因为初始权重不遵守约束吗?如果是这样,我该如何修改它,理想情况下我想将投资组合的当前权重作为 x0 传递给它。
在 b) 中,我得到了最佳解决方案 [-0.1, -0.4, 0.4, 0.1] 但我得到的 result.success 为 False。
我也收到这条消息:
Positive directional derivative for linesearch (Exit mode 8)
Current function value: -0.23999999999776675
Iterations: 8
Function evaluations: 34
Gradient evaluations: 4
我认为这条消息可能意味着它无法随着变化而增加/减少目标函数,因此它不知道它是否至少,如果我错了,请纠正我。尽管我不太确定如何以最佳方式设置它,但我尝试过使用 ftol 设置无济于事。
有没有办法修改这个优化器,以便 a) 它达到最佳解决方案并相应地产生正确的状态,并且 b) 可以采用不符合约束的初始权重?未来的希望是还包括部门和行业限制,这样我就不会在某些领域过度投资。
另外,作为一个附带问题(尽管不像我想让它开始工作那么重要):我如何实施最小交易限制?我希望股票根本不交易,或者它的交易价值超过这个数量,或者交易掉它的全部价值(如果它小于投资组合中的 min_trade 权重,则权重为零)。
正如您所看到的,这是一个很长的问题,但我非常感谢您能为这个问题提供的任何帮助、指导或答案!请要求任何澄清或额外信息,因为这花了我很长时间才拼凑起来,而且我可能没有很好地解释某些东西或遗漏了一些东西。谢谢!