优化投资组合:DolphinDB 最优化求解系列函数应用指南

本文主要是介绍优化投资组合:DolphinDB 最优化求解系列函数应用指南,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

线性规划和非线性规划是运筹学中重要的内容,在金融和经济领域的问题解决中具有广泛的应用。在金融量化领域的多因子量化模型中,组合权重优化起着至关重要的作用,组合权重优化包括两个要素:第一是组合权重优化的目标函数,如最大化期望收益率,最小化组合风险,最大化效用函数等,第二是目标函数相对应的约束条件,如等式约束和不等式约束。这些优化内容都是线性规划和非线性规划的重要应用问题。

在多因子量化投资领域中,不管使用什么因子,其最终目标都是组合优化得到标的的配置权重,这一步也叫战术配置,主要在于通过一些约束控制住风险。

多因子量化投资的整体逻辑是将 alpha 模型和 risk 模型结合在一起。我们下面以均值 - 方差组合优化框架(Mean-Varaince Optimization,MVO)为例进行解释。MVO 是由 Markowitz 于 1952 年提出,假设

为 n 支股票的目标主动权重,其中:

 为 alpha 模型得到的期望收益率,\sum 为收益率的协方差矩阵。

MVO 的一般框架为:

目标函数:

约束:

  • 约束:

    权重关系:
     

    跟踪误差:

    换手率约束:
     

    权重上下限:

    风险因子暴露:

    股票数量约束:

    其中 \omega 为 n 支股票的目标绝对权重向量,

    为股票的初始权重向量,

    为基准组合的权重向量,\lambda为交易成本的厌恶系数。

为了满足不同场景的需要,针对实际应用中不同的目标函数和约束条件建立的最优化模型,DolphinDB 提供了多个最优化函数。对于现实中的各种业务决策问题,我们都需要首先把业务问题建成数学规划模型,进而选择合适的求解器寻求最优解或者可行解,从而协助我们做出更理想的决策。通常的求解思路是:

  1. 明确业务条件与需求;
  2. 确定优化问题三要素:决策变量、目标函数、约束条件;
  3. 选择并建立合适的数学规划模型;
  4. 将该模型导入到求解器中去求解。

本教程将从最优化模型与实际投资组合优化问题出发,对 DophinDB 中最优化求解函数的使用进行介绍。

1. 最优化求解系列函数介绍

DolphinDB 最优化求解函数主要有 linprog,quadprog,qclp,socp,用于求解不同约束下的多种规划问题。

1.1 linprog(线性规划)函数

linprog 完整名称为 Linear Programming,即线性规划,用于求解线性目标函数在线性约束条件下的极值。

数学模型:

在上面的公式中,x 是未知变量,在优化问题中我们一般也称之为决策变量,min 表示求表达式 fTx 关于 x 的极小化,such that 后面的内容表示约束条件,在大括号内的三个式子表示相应的等式约束和不等式约束。可以观察到上述表达式关于 x 都是线性的,这种目标函数和约束条件都为线性的优化问题被称为线性规划问题。

对于极大化问题,仅需在目标函数前面添加负号即可转换成极小化问题。

1.2 quadprog(二次规划)函数

quadprog 即 Quadratic Programming,用于求解二次目标函数在线性约束条件下的极值。

数学模型:

其中H必须是对称正定矩阵。

可以观察到与线性规划问题相比,该模型中的目标函数中多了关于 x 的二次项。

1.3 qclp(二次约束线性规划)函数

qclp 全称为 Quadratically Constrained Linear Programming,即二次约束线性规划,该函数用于求解线性目标函数在包含二次约束条件下的极值。

数学模型:

可以观察到与线性规划问题相比,该模型中增加了非线性不等式约束和向量绝对值不等式约束。

1.4 socp(二阶锥规划)函数

socp 用于求解二阶锥规划(SOCP, Second Order Cone Programming)问题,其数学模型具有更强的一般性,有很广泛的适用场景。 socp 和 python 里的 cvxpy 库中的 ecos 求解方法是同种算法。

数学模型:

首先给出 k 维标准锥形式的定义:

二阶锥里面用到的是二范数:

SOCP 问题的锥表述形式如下:

其中,

为锥,s 为松弛变量,在实际 socp 函数参数中无对应项,其值在优化过程中会被确定。

SOCP 问题的标准形式:

其中

 为锥约束。

注:与锥表述形式相比,二阶锥的标准形式与 Gx + s = h 的对应关系为:

矩阵 G 的形式为

​向量 h 的形式为

1.5 插件介绍

gurobi 是一个性能优异、求解问题类型丰富的优化器,在国内外市场有着众多成熟的案例与客户。

gurobi 插件(预计4月中旬发布)用于调用 gurobi 优化器,遵循了原用户的使用习惯,方便用户将基于 gurobi 构建的应用与DolphinDB 进行集成。除此之外,还解决了gurobi 软件使用中的一些痛点问题:减少了数据在软件架构中的传输与计算成本,直接在 DolphinDB 库内计算,提高整体求解的效率及降低上手难度(开发人员熟悉DolphinDB 脚本语言即可)。

目前插件支持对接 Gurobi Optimizer version 10.0.2,支持 lp、qp、qclp 问题的求解,提供如下的接口。该插件预计 4 月初上线官网——插件广场。

接口参数(如无注明均为必填项)功能
modelparams:配置项,可选。<string, string> 类型的字典,用于初始化模型初始化一个模型对象
addVarsmodel:模型对象lb:变量的下限,double vectorub:变量的上限,double vectortype:变量的类型,char vector ,根据 gurobi c++ api 文档取值,可选varName:变量的名称,string vector批量增加变量
linExprmodel:模型对象coefficient:系数向量,类型为 double vectorvarName:类型为 string vector增加线性表达式
quadExprmodel:模型对象quadMatrix:类型为 double matrixvarName:类型为 string vectorlinExpr:类型为 linExpr handle增加二次表达式
addConstrmodel:类型为 model handlelhsExpr:约束表达式sense:类型为 char'<': GRB_LESS_EQUAL'>': GRB_GREATER_EQUAL'=': GRB_EQUALrhsVal:类型为 double增加线性/二次约束
setObjectivemodel:模型对象设定目标函数
optimizemodel:模型对象执行优化
getResultmodel:模型对象获取优化后的变量值
getObjectivemodel:模型对象获取优化结果

下文测试数据基于 guorbi 单用户许可,限制2000个变量和约束。

2. 常用规划问题转化为二阶锥规划形式

在使用 socp 求解一般的规划问题时,需要将原问题转化为 SOCP 问题的标准形式,再根据二阶锥的锥表述形式与标准形式之间的对应关系得到最终 socp 函数的参数。

2.1 线性规划的二阶锥形式

对于线性不等式约束

,移项后得到
 

同理对 x 设定上界与下界的约束

 可以转化为:

对应二阶锥的标准形式为

其中 E 为长度与 x 相同的单位矩阵。

因此得到二阶锥参数

2.2 二次不等式约束的二阶锥形式

对于二次不等式约束 

,其中 V 为正定矩阵,k 为正标量。V 可以通过 cholesky 分解得到 

,则原约束可以转化为 

,即可得到二阶锥的标准形式

锥形式参数

n 为变量 x 的长度。

2.3 绝对值约束的二阶锥形式

对于包含绝对值约束的线性规划

其中 1 范数约束即为绝对值约束

引入辅助变量

将原问题改写为关于 [xT, u1, ··· , un]T 的优化问题即可转换为二阶锥规划的形式: 

2.4 二次规划的二阶锥形式

对于目标函数中含有二次项的规划问题,引入辅助变量 

 ,由于 H 为正定矩阵,可以通过 cholesky 分解得到

,原问题改写为:

又由四边形恒等式

可以推出:

移项得到

代入到问题二次约束中即可得到

最终得到与原问题等价的规划问题

其中

3. 应用场景示例

3.1 场景一:最大化期望收益率

在股票组合优化问题中,可以在个股权重上下限约束,风险约束,行业约束的约束条件下求解股票投资组合的最大收益。假设有 10 支股票,预测它们未来的收益率分别为[0.1, 0.02, 0.01, 0.05, 0.17, 0.01, 0.07, 0.08, 0.09, 0.10]。这些股票属于消费、金融和科技三个行业,希望在每个行业的暴露不超过8%,且每个股票权重分配不得多于 15%,求最大化预期收益的投资组合。

linprog 函数求解

根据问题描述可以带入线性规划模型得到

预期收益率:

不等式约束:

等式约束:所有股票分配权重之和为 1。

f = -1*[0.1,0.02,0.01,0.05,0.17,0.01,0.07,0.08,0.09,0.10]
A = ([1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1]$10:6).transpose()
b = [0.3,0.4,0.3]
//参数设置
exposure = 0.08
b = (b + exposure) join (exposure - b)
Aeq = matrix(take(1, size(f))).transpose()
beq = array(DOUBLE).append!(1)
res = linprog(f, A, b, Aeq, beq, 0, 0.15)//输出结果 
max_return = -res[0] 
//max_return = 0.0861
weights = res[1]
//weights = [0.15,0.15,0,0.15,0.15,0.02,0,0.08,0.15,0.15]

gurobi 插件求解

loadPlugin("plugins/gurobi/PluginGurobi.txt")
model = gurobi::model()/// 增加变量
numOfVars = 10
lb = take(0, numOfVars)
ub = take(0.15, numOfVars)
stocks = ["A001", "A002", "A003", "A004", "A005", "A006", "A007", "A008", "A009", "A010"]
vars = gurobi::addVars(model, lb, ub, , , stocks)/// 增加线性约束
f = [0.1,0.02,0.01,0.05,0.17,0.01,0.07,0.08,0.09,0.10]
A = ([1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,-1,-1,-1,-1]$10:6)
rhs = 0.38 0.48 0.38 -0.22 -0.32 -0.22for (i in 0:6) {lhsExpr = gurobi::linExpr(model, A[i], stocks)gurobi::addConstr(model, lhsExpr, '<', rhs[i])
}lhsExpr = gurobi::linExpr(model, take(1, numOfVars), stocks)
gurobi::addConstr(model, lhsExpr, '=', 1)// 设置目标函数
obj = gurobi::linExpr(model, f, vars)
gurobi::setObjective(model, obj, -1)// 执行优化
gurobi::optimize(model) // 获取优化结果
result = gurobi::getResult(model)
//股票权重:result = [0.15,0.15,0,0.15,0.15,0.02,0,0.08,0.15,0.15]
obj = gurobi::getObjective(model)
//目标值:obj = 0.0861

3.2 场景二:最大化效用函数

现代投资组合理论用均值和方差来刻画收益和风险这两个关键因素,效用函数期望则是尽可能的在最大化期望收益率和最小组合波动率之间取得一个平衡,二次目标函数的最优解也是组合权重优化的一部分,一般收益最大化的同时也要求组合风险最小。

假设有 2457 支股票,其投资组合收益率的协方差矩阵是一个单位矩阵,求解在取得最大效用函数的时各股票的权重分配。

quadprog 函数求解

baseDir = "/home/data/"
f = dropna(flatten(float(matrix(select col1, col2, col3, col4, col5, col6, col7, col8, col9, col10 from loadText(baseDir + "C.csv") where rowNo(col1) > 0)).transpose()))N = f.size()
H = eye(N) //协方差矩阵
A = matrix(select * from loadText(baseDir + "A_ub.csv"))
b = 
[0.025876723,	0.092515275,	0.035133942,	0.053184884,	0.067410565,	0.009709433,	0.04668745,	0.00636804,	0.022258664,	0.11027537,
0.018488302,	0.027417204,	0.028585,	0.017228214,	0.008055527,	0.015727843,	0.026132369,	0.013646113,	0.066000808,	0.043606587,
0.048325258,	0.033868626,	0.010790603,	0.017737391,	0.03252374,	0.039329965,	0.040665779,	0.010868773,	0.006819891,	0.015879314,
0.008882335,	-0.025876723,	-0.092515275,	-0.035133942,	-0.053184884,	-0.067410565,	-0.009709433,	-0.04668745,	-0.00636804,	-0.022258664,
-0.110275379,	-0.018488302,	-0.027417204,	-0.028585,	-0.017228214,	-0.008055527,	-0.015727843,	-0.026132369,	-0.013646113,	-0.066000808,
-0.043606587,	-0.048325258,	-0.033868626,	-0.010790603,	-0.017737391,	-0.03252374,	-0.039329965,	-0.040665779,	-0.010868773,	-0.006819891,
-0.015879314,	-0.008882335]//线性约束
Aeq = matrix(take(1, N)).transpose()
beq = array(DOUBLE).append!(1)
res2 = quadprog(H, f, A, b, Aeq, beq)

gurobi 插件求解

baseDir="/home/data/"
f = dropna(flatten(double(matrix(select col1, col2, col3, col4, col5, col6, col7, col8, col9, col10 from loadText(baseDir + "C.csv") where rowNo(col1) > 0)).transpose()))N = f.size()
H = eye(N)
A = matrix(select * from loadText(baseDir + "A_ub.csv")).transpose()
b = 
[0.025876723,	0.092515275,	0.035133942,	0.053184884,	0.067410565,	0.009709433,	0.04668745,	0.00636804,	0.022258664,	0.11027537,
0.018488302,	0.027417204,	0.028585,	0.017228214,	0.008055527,	0.015727843,	0.026132369,	0.013646113,	0.066000808,	0.043606587,
0.048325258,	0.033868626,	0.010790603,	0.017737391,	0.03252374,	0.039329965,	0.040665779,	0.010868773,	0.006819891,	0.015879314,
0.008882335,	-0.025876723,	-0.092515275,	-0.035133942,	-0.053184884,	-0.067410565,	-0.009709433,	-0.04668745,	-0.00636804,	-0.022258664,
-0.110275379,	-0.018488302,	-0.027417204,	-0.028585,	-0.017228214,	-0.008055527,	-0.015727843,	-0.026132369,	-0.013646113,	-0.066000808,
-0.043606587,	-0.048325258,	-0.033868626,	-0.010790603,	-0.017737391,	-0.03252374,	-0.039329965,	-0.040665779,	-0.010868773,	-0.006819891,
-0.015879314,	-0.008882335]model = gurobi::model()
/// 增加变量
lb = take(-10, N)
ub = take(10, N)
varName = "v" + string(1..N)
vars = gurobi::addVars(model, lb, ub, , ,varName)//增加线性约束
for (i in 0:N) {lhsExpr = gurobi::linExpr(model, A[i], varName)gurobi::addConstr(model, lhsExpr, '<', b[i])
}
lhsExpr = gurobi::linExpr(model, take(1, N), varName)
gurobi::addConstr(model, lhsExpr, '=', 1)// 增加目标值
linExpr = gurobi::linExpr(model, f, vars)
quadExpr = gurobi::quadExpr(model, H, varName, linExpr)
gurobi::setObjective(model, quadExpr, 1)timer status = gurobi::optimize(model) // 获取优化结果
result = gurobi::getResult(model)
obj = gurobi::getObjective(model)

3.3 场景三:带有换手率约束的投资组合问题

同样是场景二中的 2457 支股票,我们引入换手率约束。在投资组合问题中,换手率即为当前股票权重与初始股票权重的绝对值之和,衡量了股票的流通性大小。过高的换手率意味着较大的交易成本,本例中我们设置所有股票换手率之和不大于1,求解使投资组合达到最大收益率时的权重分配。

socp 函数求解

使用socp函数求解带有换手率约束的投资组合问题时,需将原问题转化为含有绝对值约束的二阶锥形式再进行求解。

baseDir = "/home/data/""
f = dropna(flatten(float(matrix(select col1, col2, col3, col4, col5, col6, col7, col8, col9, col10 from loadText(baseDir + "C.csv") where rowNo(col1) > 0)).transpose()))
N = f.size()// Ax <= b
A = matrix(select * from loadText(baseDir + "A_ub.csv"))
x = sum(A[0,])
sum(x);b = 
[0.025876723,	0.092515275,	0.035133942,	0.053184884,	0.067410565,	0.009709433,	0.04668745,	0.00636804,	0.022258664,	0.11027537,
0.018488302,	0.027417204,	0.028585,	0.017228214,	0.008055527,	0.015727843,	0.026132369,	0.013646113,	0.066000808,	0.043606587,
0.048325258,	0.033868626,	0.010790603,	0.017737391,	0.03252374,	0.039329965,	0.040665779,	0.010868773,	0.006819891,	0.015879314,
0.008882335,	-0.025876723,	-0.092515275,	-0.035133942,	-0.053184884,	-0.067410565,	-0.009709433,	-0.04668745,	-0.00636804,	-0.022258664,
-0.110275379,	-0.018488302,	-0.027417204,	-0.028585,	-0.017228214,	-0.008055527,	-0.015727843,	-0.026132369,	-0.013646113,	-0.066000808,
-0.043606587,	-0.048325258,	-0.033868626,	-0.010790603,	-0.017737391,	-0.03252374,	-0.039329965,	-0.040665779,	-0.010868773,	-0.006819891,
-0.015879314,	-0.008882335]x0 = exec w0 from  loadText(baseDir + "w0.csv") // minimize f^T * x + 0 * u , c = [f, 0] 引入新的求解变量
c = -f // f^T * x, 
c.append!(take(0, N)) // 0 * u
c;// 根据二阶锥的锥形式与标准形式对应关系设置矩阵 G 
E = eye(N)
zeros = matrix(DOUBLE, N, N, ,0)G = concatMatrix([-E,zeros]) // -x <= -lb 
G = concatMatrix([G, concatMatrix([E,zeros])], false) // x <= ub
G = concatMatrix([G, concatMatrix([E,-E])], false) // x_i -u_i <= x`_i 
G = concatMatrix([G, concatMatrix([-E,-E])], false) // -x_i-u_i <= -x`_iG = concatMatrix([G, concatMatrix([matrix(DOUBLE,1,N,,0), matrix(DOUBLE,1,N,,1)])], false) // sum(u)=c
G = concatMatrix([G, concatMatrix([A, matrix(DOUBLE,b.size(), N,,0)])], false) // A*x <= b//根据二阶锥的锥形式与标准形式对应关系设置向量 h
h = array(DOUBLE).append!(take(0, N)) // -x <= -lb
h.append!(take(0.3, N)) // x <= ub
h.append!(x0) // x_i -u_i <= x`_i
h.append!(-x0) // -x_i-u_i <= -x`_i
h.append!(1) // sum(u)<=c 换手率约束
h.append!(b) // A*x <= b // l, q
l = 9891 // 所有约束都是线性的
q = []// Aeq, beq
Aeq = concatMatrix([matrix(DOUBLE, 1, N, ,1), matrix(DOUBLE, 1, N, ,0)])
beq = array(DOUBLE).append!(1)res = socp(c, G, h, l, q, Aeq, beq);
print(res)
// output > ("Problem solved to optimality",[4.030922466819474E-13,-1.38420918319221E-12,2.633003706864388E-12,7.170457424061185E-12,3.08367186410226E-13,-1.538707717541051E-12,0.00029999999826,4.494868392653513E-12,-1.046866787477076E-12,0.000799999998839,1.16264810755163E-12,1.610142862543512E-11,-1.056487154243985E-13,-2.157448203710766E-13,4.389916149869339E-12,1.875852354004975E-12,7.82477001121239E-12,0.001299999997416,4.727903065768357E-13,7.550671346161244E-13,5.591928646425624E-12,1.124989684680735E-11,5.482907889730026E-12,0.015985000026396,0.000700000000029,5.633638482685261E-12,1.67297174174449E-12,5.469150816162936E-12,-6.300522047286838E-13,2.303301153098362E-12...],0.964278008555949)

gurobi 插件求解

暂不支持圆锥约束的求解。

3.4 场景四:带有收益率波动约束的投资组合问题

有三支股票,根据每支股票的预期收益与收益率协方差矩阵,决定最优投资组合。

约束条件为:

  1. 投资组合的收益率的波动率不超过 11%;
  2. 每支股票的权重在 10% 到 50% 之间。

qclp 函数求解

r = 0.18 0.25 0.36
V = 0.0225 -0.003 -0.01125 -0.003 0.04 0.025 -0.01125 0.025 0.0625 $ 3:3
k = pow(0.11, 2)
A = (eye(3) join (-1 * eye(3))).transpose()
b = 0.5 0.5 0.5 -0.1 -0.1 -0.1
Aeq = (1 1 1)$1:3
beq = [1]res = qclp(-r, V, k, A, b, Aeq, beq) 
//输出结果
max_return = res[0]
//max_return = 0.2281
weights = res[1]
//weights = [0.50, 0.381, 0.119]

gurobi 插件求解

r = 0.18 0.25 0.36
V = 0.0225 -0.003 -0.01125 -0.003 0.04 0.025 -0.01125 0.025 0.0625 $ 3:3
k = pow(0.11, 2)
A = (eye(3) join (-1 * eye(3)))
b = 0.5 0.5 0.5 -0.1 -0.1 -0.1// 初始化模型及变量
model = gurobi::model()
varNames = "v" + string(1..3)
lb = 0 0 0
ub = 1 1 1
vars = gurobi::addVars(model, lb, ub,,, varNames)//增加线性约束
for (i in 0:3) {lhsExpr = gurobi::linExpr(model, A[i], vars)gurobi::addConstr(model, lhsExpr, '<', b[i])
}
lhsExpr = gurobi::linExpr(model, take(1, 3), vars)
gurobi::addConstr(model, lhsExpr, '=', 1)// 增加二次约束
quadExp = gurobi::quadExpr(model, V, vars)
gurobi::addConstr(model, quadExp, '<', k)//设置目标值并执行优化
obj = gurobi::linExpr(model, r, vars)
gurobi::setObjective(model, obj, 1)
timer gurobi::optimize(model)// 获取优化结果
result = gurobi::getResult(model) 
// [0.50, 0.3808, 0.119158]
obj = gurobi::getObjective(model)
// 0.228107

4. DolphinDB 与 Python 求解最优化问题性能对比

socp 作为 DolphinDB 最优化求解系列函数中适用场景最广泛的优化问题求解器,很多优化问题都可以转换为二阶锥规划后使用 socp 求解。并且由于二阶锥规划具有非常高效的求解算法,因此 socp 函数具有很高的求解效率。 socp 和 python 里的 cvxpy 库中的 ecos 求解方法一致。

本节通过使用随机模拟数据对三类规划问题使用不同求解方法的性能进行了对比。需要注意的是,不同的数据可能会对运算性能产生一定影响,因此本测试用例仅供参考。

4.1 线性规划问题(LP)

使用函数用时统计
linprog25.9 ms
socp111.6ms
scipy.optimize.linprog(python)38.9 ms
gurobi 插件1.0 ms

本测试场景使用 200 个变量,其中插件的耗时包括从模型初始化至执行optimize 求解的全部过程(下同)。

4.2 二次规划问题(QP)

使用函数用时统计
quadprog2,877.6 ms
socp11,625.3 ms
cvxpy(python)8,809.7ms
gurobi 插件4601.7 ms

本测试场景使用 1000 个变量,其中 gurobi 插件在添加约束时耗时较大(773.0 ms),实际优化耗时3,828.7 ms。

4.3 二次约束线性规划问题(QCLP)

使用函数用时统计
qclp121.6 ms
socp30.1 ms
cvxpy(python)353.6ms
gurobi 插件1.1ms

本测试场景使用 200 个变量。

从以上性能对比可以看出,总体而言,gurobi 插件展现出最佳的求解性能,而 DolphinDB 的内置函数相比 python 的求解器也表现出更快的求解速率。此外使用 DolphinDB 最优化函数、gurobi 插件求解的结果与 Python 的求解结果在小数点后至少四位内均达到一致。

5. 小结

对于组合优化的场景,DolphinDB 提供了内置的最优化函数及插件的解决方案。使用内置函数时,相较于其他最优化函数,二阶锥规划(socp)展现出广泛的适用范围和强大的运算性能。在实际应用中,通过将一般规划问题转化为二阶锥问题并进行求解,往往能够获得更优的结果。如果项目中已经使用了 gurobi 求解器,选择插件不失为一种优秀的工程方案。结合 DolphinDB 在高性能行情数据处理上的优势,便捷、高效地实现组合优化。

6. 附录

DolphinDB 与 Python 求解最优化问题以及性能对比的数据与实现脚本。

  • data.zip
  • script.zip

这篇关于优化投资组合:DolphinDB 最优化求解系列函数应用指南的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/826204

相关文章

SQLite3命令行工具最佳实践指南

《SQLite3命令行工具最佳实践指南》SQLite3是轻量级嵌入式数据库,无需服务器支持,具备ACID事务与跨平台特性,适用于小型项目和学习,sqlite3.exe作为命令行工具,支持SQL执行、数... 目录1. SQLite3简介和特点2. sqlite3.exe使用概述2.1 sqlite3.exe

Python中help()和dir()函数的使用

《Python中help()和dir()函数的使用》我们经常需要查看某个对象(如模块、类、函数等)的属性和方法,Python提供了两个内置函数help()和dir(),它们可以帮助我们快速了解代... 目录1. 引言2. help() 函数2.1 作用2.2 使用方法2.3 示例(1) 查看内置函数的帮助(

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

从基础到进阶详解Pandas时间数据处理指南

《从基础到进阶详解Pandas时间数据处理指南》Pandas构建了完整的时间数据处理生态,核心由四个基础类构成,Timestamp,DatetimeIndex,Period和Timedelta,下面我... 目录1. 时间数据类型与基础操作1.1 核心时间对象体系1.2 时间数据生成技巧2. 时间索引与数据

Java SWT库详解与安装指南(最新推荐)

《JavaSWT库详解与安装指南(最新推荐)》:本文主要介绍JavaSWT库详解与安装指南,在本章中,我们介绍了如何下载、安装SWTJAR包,并详述了在Eclipse以及命令行环境中配置Java... 目录1. Java SWT类库概述2. SWT与AWT和Swing的区别2.1 历史背景与设计理念2.1.

Redis过期删除机制与内存淘汰策略的解析指南

《Redis过期删除机制与内存淘汰策略的解析指南》在使用Redis构建缓存系统时,很多开发者只设置了EXPIRE但却忽略了背后Redis的过期删除机制与内存淘汰策略,下面小编就来和大家详细介绍一下... 目录1、简述2、Redis http://www.chinasem.cn的过期删除策略(Key Expir

SpringBoot整合Apache Flink的详细指南

《SpringBoot整合ApacheFlink的详细指南》这篇文章主要为大家详细介绍了SpringBoot整合ApacheFlink的详细过程,涵盖环境准备,依赖配置,代码实现及运行步骤,感兴趣的... 目录1. 背景与目标2. 环境准备2.1 开发工具2.2 技术版本3. 创建 Spring Boot

Python远程控制MySQL的完整指南

《Python远程控制MySQL的完整指南》MySQL是最流行的关系型数据库之一,Python通过多种方式可以与MySQL进行交互,下面小编就为大家详细介绍一下Python操作MySQL的常用方法和最... 目录1. 准备工作2. 连接mysql数据库使用mysql-connector使用PyMySQL3.

Linux中修改Apache HTTP Server(httpd)默认端口的完整指南

《Linux中修改ApacheHTTPServer(httpd)默认端口的完整指南》ApacheHTTPServer(简称httpd)是Linux系统中最常用的Web服务器之一,本文将详细介绍如何... 目录一、修改 httpd 默认端口的步骤1. 查找 httpd 配置文件路径2. 编辑配置文件3. 保存

Python中文件读取操作漏洞深度解析与防护指南

《Python中文件读取操作漏洞深度解析与防护指南》在Web应用开发中,文件操作是最基础也最危险的功能之一,这篇文章将全面剖析Python环境中常见的文件读取漏洞类型,成因及防护方案,感兴趣的小伙伴可... 目录引言一、静态资源处理中的路径穿越漏洞1.1 典型漏洞场景1.2 os.path.join()的陷