siat 3.10.131__py3-none-any.whl → 3.10.132__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- build/lib/build/lib/siat/__init__.py +75 -0
- build/lib/build/lib/siat/allin.py +137 -0
- build/lib/build/lib/siat/assets_liquidity.py +915 -0
- build/lib/build/lib/siat/beta_adjustment.py +1058 -0
- build/lib/build/lib/siat/beta_adjustment_china.py +548 -0
- build/lib/build/lib/siat/blockchain.py +143 -0
- build/lib/build/lib/siat/bond.py +2900 -0
- build/lib/build/lib/siat/bond_base.py +992 -0
- build/lib/build/lib/siat/bond_china.py +100 -0
- build/lib/build/lib/siat/bond_zh_sina.py +143 -0
- build/lib/build/lib/siat/capm_beta.py +783 -0
- build/lib/build/lib/siat/capm_beta2.py +887 -0
- build/lib/build/lib/siat/common.py +5360 -0
- build/lib/build/lib/siat/compare_cross.py +642 -0
- build/lib/build/lib/siat/copyrights.py +18 -0
- build/lib/build/lib/siat/cryptocurrency.py +667 -0
- build/lib/build/lib/siat/economy.py +1471 -0
- build/lib/build/lib/siat/economy2.py +1853 -0
- build/lib/build/lib/siat/esg.py +536 -0
- build/lib/build/lib/siat/event_study.py +815 -0
- build/lib/build/lib/siat/fama_french.py +1521 -0
- build/lib/build/lib/siat/fin_stmt2_yahoo.py +982 -0
- build/lib/build/lib/siat/financial_base.py +1160 -0
- build/lib/build/lib/siat/financial_statements.py +598 -0
- build/lib/build/lib/siat/financials.py +2339 -0
- build/lib/build/lib/siat/financials2.py +1278 -0
- build/lib/build/lib/siat/financials_china.py +4433 -0
- build/lib/build/lib/siat/financials_china2.py +2212 -0
- build/lib/build/lib/siat/fund.py +629 -0
- build/lib/build/lib/siat/fund_china.py +3307 -0
- build/lib/build/lib/siat/future_china.py +551 -0
- build/lib/build/lib/siat/google_authenticator.py +47 -0
- build/lib/build/lib/siat/grafix.py +3636 -0
- build/lib/build/lib/siat/holding_risk.py +867 -0
- build/lib/build/lib/siat/luchy_draw.py +638 -0
- build/lib/build/lib/siat/market_china.py +1168 -0
- build/lib/build/lib/siat/markowitz.py +2363 -0
- build/lib/build/lib/siat/markowitz2.py +3150 -0
- build/lib/build/lib/siat/markowitz2_20250704.py +2969 -0
- build/lib/build/lib/siat/markowitz2_20250705.py +3158 -0
- build/lib/build/lib/siat/markowitz_simple.py +373 -0
- build/lib/build/lib/siat/ml_cases.py +2291 -0
- build/lib/build/lib/siat/ml_cases_example.py +60 -0
- build/lib/build/lib/siat/option_china.py +3069 -0
- build/lib/build/lib/siat/option_pricing.py +1925 -0
- build/lib/build/lib/siat/other_indexes.py +409 -0
- build/lib/build/lib/siat/risk_adjusted_return.py +1576 -0
- build/lib/build/lib/siat/risk_adjusted_return2.py +1900 -0
- build/lib/build/lib/siat/risk_evaluation.py +2218 -0
- build/lib/build/lib/siat/risk_free_rate.py +351 -0
- build/lib/build/lib/siat/sector_china.py +4140 -0
- build/lib/build/lib/siat/security_price2.py +727 -0
- build/lib/build/lib/siat/security_prices.py +3408 -0
- build/lib/build/lib/siat/security_trend.py +402 -0
- build/lib/build/lib/siat/security_trend2.py +646 -0
- build/lib/build/lib/siat/stock.py +4284 -0
- build/lib/build/lib/siat/stock_advice_linear.py +934 -0
- build/lib/build/lib/siat/stock_base.py +26 -0
- build/lib/build/lib/siat/stock_china.py +2095 -0
- build/lib/build/lib/siat/stock_prices_kneighbors.py +910 -0
- build/lib/build/lib/siat/stock_prices_linear.py +386 -0
- build/lib/build/lib/siat/stock_profile.py +707 -0
- build/lib/build/lib/siat/stock_technical.py +3305 -0
- build/lib/build/lib/siat/stooq.py +74 -0
- build/lib/build/lib/siat/transaction.py +347 -0
- build/lib/build/lib/siat/translate.py +5183 -0
- build/lib/build/lib/siat/valuation.py +1378 -0
- build/lib/build/lib/siat/valuation_china.py +2076 -0
- build/lib/build/lib/siat/var_model_validation.py +444 -0
- build/lib/build/lib/siat/yf_name.py +811 -0
- build/lib/siat/__init__.py +75 -0
- build/lib/siat/allin.py +137 -0
- build/lib/siat/assets_liquidity.py +915 -0
- build/lib/siat/beta_adjustment.py +1058 -0
- build/lib/siat/beta_adjustment_china.py +548 -0
- build/lib/siat/blockchain.py +143 -0
- build/lib/siat/bond.py +2900 -0
- build/lib/siat/bond_base.py +992 -0
- build/lib/siat/bond_china.py +100 -0
- build/lib/siat/bond_zh_sina.py +143 -0
- build/lib/siat/capm_beta.py +783 -0
- build/lib/siat/capm_beta2.py +887 -0
- build/lib/siat/common.py +5360 -0
- build/lib/siat/compare_cross.py +642 -0
- build/lib/siat/copyrights.py +18 -0
- build/lib/siat/cryptocurrency.py +667 -0
- build/lib/siat/economy.py +1471 -0
- build/lib/siat/economy2.py +1853 -0
- build/lib/siat/esg.py +536 -0
- build/lib/siat/event_study.py +815 -0
- build/lib/siat/fama_french.py +1521 -0
- build/lib/siat/fin_stmt2_yahoo.py +982 -0
- build/lib/siat/financial_base.py +1160 -0
- build/lib/siat/financial_statements.py +598 -0
- build/lib/siat/financials.py +2339 -0
- build/lib/siat/financials2.py +1278 -0
- build/lib/siat/financials_china.py +4433 -0
- build/lib/siat/financials_china2.py +2212 -0
- build/lib/siat/fund.py +629 -0
- build/lib/siat/fund_china.py +3307 -0
- build/lib/siat/future_china.py +551 -0
- build/lib/siat/google_authenticator.py +47 -0
- build/lib/siat/grafix.py +3636 -0
- build/lib/siat/holding_risk.py +867 -0
- build/lib/siat/luchy_draw.py +638 -0
- build/lib/siat/market_china.py +1168 -0
- build/lib/siat/markowitz.py +2363 -0
- build/lib/siat/markowitz2.py +3150 -0
- build/lib/siat/markowitz2_20250704.py +2969 -0
- build/lib/siat/markowitz2_20250705.py +3158 -0
- build/lib/siat/markowitz_simple.py +373 -0
- build/lib/siat/ml_cases.py +2291 -0
- build/lib/siat/ml_cases_example.py +60 -0
- build/lib/siat/option_china.py +3069 -0
- build/lib/siat/option_pricing.py +1925 -0
- build/lib/siat/other_indexes.py +409 -0
- build/lib/siat/risk_adjusted_return.py +1576 -0
- build/lib/siat/risk_adjusted_return2.py +1900 -0
- build/lib/siat/risk_evaluation.py +2218 -0
- build/lib/siat/risk_free_rate.py +351 -0
- build/lib/siat/sector_china.py +4140 -0
- build/lib/siat/security_price2.py +727 -0
- build/lib/siat/security_prices.py +3408 -0
- build/lib/siat/security_trend.py +402 -0
- build/lib/siat/security_trend2.py +646 -0
- build/lib/siat/stock.py +4284 -0
- build/lib/siat/stock_advice_linear.py +934 -0
- build/lib/siat/stock_base.py +26 -0
- build/lib/siat/stock_china.py +2095 -0
- build/lib/siat/stock_prices_kneighbors.py +910 -0
- build/lib/siat/stock_prices_linear.py +386 -0
- build/lib/siat/stock_profile.py +707 -0
- build/lib/siat/stock_technical.py +3305 -0
- build/lib/siat/stooq.py +74 -0
- build/lib/siat/transaction.py +347 -0
- build/lib/siat/translate.py +5183 -0
- build/lib/siat/valuation.py +1378 -0
- build/lib/siat/valuation_china.py +2076 -0
- build/lib/siat/var_model_validation.py +444 -0
- build/lib/siat/yf_name.py +811 -0
- siat/__init__.py +0 -0
- siat/allin.py +0 -0
- siat/assets_liquidity.py +0 -0
- siat/beta_adjustment.py +0 -0
- siat/beta_adjustment_china.py +0 -0
- siat/blockchain.py +0 -0
- siat/bond.py +0 -0
- siat/bond_base.py +0 -0
- siat/bond_china.py +0 -0
- siat/bond_zh_sina.py +0 -0
- siat/capm_beta.py +0 -0
- siat/capm_beta2.py +0 -0
- siat/common.py +136 -3
- siat/compare_cross.py +0 -0
- siat/copyrights.py +0 -0
- siat/cryptocurrency.py +0 -0
- siat/economy.py +0 -0
- siat/economy2.py +0 -0
- siat/esg.py +0 -0
- siat/event_study.py +0 -0
- siat/exchange_bond_china.pickle +0 -0
- siat/fama_french.py +0 -0
- siat/fin_stmt2_yahoo.py +0 -0
- siat/financial_base.py +0 -0
- siat/financial_statements.py +0 -0
- siat/financials.py +0 -0
- siat/financials2.py +0 -0
- siat/financials_china.py +0 -0
- siat/financials_china2.py +0 -0
- siat/fund.py +0 -0
- siat/fund_china.pickle +0 -0
- siat/fund_china.py +0 -0
- siat/future_china.py +0 -0
- siat/google_authenticator.py +0 -0
- siat/grafix.py +1 -1
- siat/holding_risk.py +0 -0
- siat/luchy_draw.py +0 -0
- siat/market_china.py +1 -1
- siat/markowitz.py +0 -0
- siat/markowitz2.py +240 -39
- siat/markowitz2_20250704.py +2969 -0
- siat/markowitz2_20250705.py +3158 -0
- siat/markowitz_simple.py +0 -0
- siat/ml_cases.py +0 -0
- siat/ml_cases_example.py +0 -0
- siat/option_china.py +0 -0
- siat/option_pricing.py +0 -0
- siat/other_indexes.py +0 -0
- siat/risk_adjusted_return.py +0 -0
- siat/risk_adjusted_return2.py +0 -0
- siat/risk_evaluation.py +0 -0
- siat/risk_free_rate.py +0 -0
- siat/sector_china.py +0 -0
- siat/security_price2.py +0 -0
- siat/security_prices.py +3 -1
- siat/security_trend.py +0 -0
- siat/security_trend2.py +1 -1
- siat/stock.py +4 -2
- siat/stock_advice_linear.py +0 -0
- siat/stock_base.py +0 -0
- siat/stock_china.py +0 -0
- siat/stock_info.pickle +0 -0
- siat/stock_prices_kneighbors.py +0 -0
- siat/stock_prices_linear.py +0 -0
- siat/stock_profile.py +0 -0
- siat/stock_technical.py +0 -0
- siat/stooq.py +0 -0
- siat/transaction.py +0 -0
- siat/translate.py +11 -11
- siat/valuation.py +0 -0
- siat/valuation_china.py +0 -0
- siat/var_model_validation.py +0 -0
- siat/yf_name.py +0 -0
- {siat-3.10.131.dist-info → siat-3.10.132.dist-info}/METADATA +235 -227
- siat-3.10.132.dist-info/RECORD +218 -0
- {siat-3.10.131.dist-info → siat-3.10.132.dist-info}/WHEEL +1 -1
- {siat-3.10.131.dist-info → siat-3.10.132.dist-info/licenses}/LICENSE +0 -0
- siat-3.10.132.dist-info/top_level.txt +4 -0
- siat-3.10.131.dist-info/RECORD +0 -76
- siat-3.10.131.dist-info/top_level.txt +0 -1
siat/markowitz2.py
CHANGED
@@ -21,6 +21,7 @@ from siat.common import *
|
|
21
21
|
from siat.translate import *
|
22
22
|
from siat.security_prices import *
|
23
23
|
from siat.security_price2 import *
|
24
|
+
from siat.grafix import *
|
24
25
|
#from siat.fama_french import *
|
25
26
|
|
26
27
|
import pandas as pd
|
@@ -172,6 +173,7 @@ def cumulative_returns_plot(retgroup,name_list="",titletxt="投资组合策略
|
|
172
173
|
xlabeltxt=footnote1+footnote2
|
173
174
|
|
174
175
|
# 持有收益曲线绘制函数
|
176
|
+
"""
|
175
177
|
lslist=['-','--',':','-.']
|
176
178
|
markerlist=['.','h','+','x','4','3','2','1']
|
177
179
|
for name in name_list:
|
@@ -196,6 +198,22 @@ def cumulative_returns_plot(retgroup,name_list="",titletxt="投资组合策略
|
|
196
198
|
|
197
199
|
plt.gca().set_facecolor(facecolor)
|
198
200
|
plt.show()
|
201
|
+
"""
|
202
|
+
import pandas as pd
|
203
|
+
df=pd.DataFrame()
|
204
|
+
for name in name_list:
|
205
|
+
# 计算持有收益率
|
206
|
+
CumulativeReturns = ((1+retgroup[name]).cumprod()-1)
|
207
|
+
|
208
|
+
df[name]=CumulativeReturns
|
209
|
+
|
210
|
+
draw_lines(df,y_label=ylabeltxt,x_label=xlabeltxt, \
|
211
|
+
axhline_value=0,axhline_label='', \
|
212
|
+
title_txt=titletxt, \
|
213
|
+
annotate=True, \
|
214
|
+
annotate_value=False, \
|
215
|
+
facecolor=facecolor, \
|
216
|
+
)
|
199
217
|
|
200
218
|
return
|
201
219
|
|
@@ -300,8 +318,8 @@ def portfolio_build(portfolio,thedate='default',pastyears=3, \
|
|
300
318
|
获取股价时的信息
|
301
319
|
是否显示原始组合、等权重组合和交易金额加权组合的成分股构成
|
302
320
|
是否显示原始组合、等权重组合和交易金额加权组合的收益风险排名
|
303
|
-
3. pastyears=3
|
304
|
-
|
321
|
+
3. pastyears=3更有可能生成斜向上的椭圆形可行集,短于3形状不佳,长于3改善形状有限。
|
322
|
+
需要与不同行业的证券搭配。同行业证券相关性较强,不易生成斜向上的椭圆形可行集。
|
305
323
|
4. 若ticker_type='fund'可能导致无法处理股票的复权价!
|
306
324
|
5. 若要指定特定的证券为债券,则需要使用列表逐一指定证券的类型(股票,债券,基金)
|
307
325
|
6. 默认采用前复权计算收益率,更加平稳
|
@@ -328,7 +346,7 @@ def portfolio_build(portfolio,thedate='default',pastyears=3, \
|
|
328
346
|
print(" #Warning(portfolio_build): invalid date",thedate)
|
329
347
|
return None
|
330
348
|
|
331
|
-
print(" Searching
|
349
|
+
print(f" Searching portfolio info for recent {pastyears} years ...")
|
332
350
|
# 解构投资组合
|
333
351
|
scope,_,tickerlist,sharelist0,ticker_type=decompose_portfolio(portfolio)
|
334
352
|
pname=portfolio_name(portfolio)
|
@@ -1150,7 +1168,7 @@ if __name__=='__main__':
|
|
1150
1168
|
|
1151
1169
|
portfolio_eset(pf_info,simulation=50000)
|
1152
1170
|
|
1153
|
-
def portfolio_feset(pf_info,simulation=
|
1171
|
+
def portfolio_feset(pf_info,simulation=10000,convex_hull=True,frontier="both",facecolor='papayawhip'):
|
1154
1172
|
"""
|
1155
1173
|
功能:套壳函数portfolio_eset
|
1156
1174
|
当frontier不在列表['efficient','inefficient','both']中时,绘制可行集
|
@@ -1158,6 +1176,7 @@ def portfolio_feset(pf_info,simulation=50000,convex_hull=True,frontier="both",fa
|
|
1158
1176
|
当frontier == 'inefficient'时绘制无效边界
|
1159
1177
|
当frontier == 'both'时同时绘制有效边界和无效边界
|
1160
1178
|
当绘制有效/无效边界时,默认使用凸包绘制(convex_hull=True)
|
1179
|
+
注:若可行集形状不佳,首先尝试pastyears=3,再尝试增加simulation数量
|
1161
1180
|
"""
|
1162
1181
|
if frontier is None:
|
1163
1182
|
convex_hull=False
|
@@ -1211,7 +1230,7 @@ def portfolio_eset(pf_info,simulation=50000,convex_hull=False,frontier="both",fa
|
|
1211
1230
|
np.random.seed(RANDOM_SEED)
|
1212
1231
|
|
1213
1232
|
# 循环模拟n次随机的投资组合
|
1214
|
-
print("
|
1233
|
+
print(f" Simulating {simulation} feasible sets of portfolios ...")
|
1215
1234
|
for i in range(simulation):
|
1216
1235
|
# 生成numstocks个随机数,并归一化,得到一组随机的权重数据
|
1217
1236
|
random9 = np.random.random(numstocks)
|
@@ -1267,6 +1286,8 @@ def portfolio_eset(pf_info,simulation=50000,convex_hull=False,frontier="both",fa
|
|
1267
1286
|
pf_returns_list=list(pf_returns)
|
1268
1287
|
points=[]
|
1269
1288
|
for x in pf_volatilities_list:
|
1289
|
+
print_progress_percent2(x,pf_volatilities_list,steps=5,leading_blanks=4)
|
1290
|
+
|
1270
1291
|
pos=pf_volatilities_list.index(x)
|
1271
1292
|
y=pf_returns_list[pos]
|
1272
1293
|
points=points+[[x,y]]
|
@@ -1348,7 +1369,10 @@ def portfolio_eset(pf_info,simulation=50000,convex_hull=False,frontier="both",fa
|
|
1348
1369
|
else:
|
1349
1370
|
pass
|
1350
1371
|
else:
|
1351
|
-
|
1372
|
+
pass
|
1373
|
+
|
1374
|
+
# 空一行
|
1375
|
+
print('')
|
1352
1376
|
|
1353
1377
|
|
1354
1378
|
import datetime as dt; stoday=dt.date.today()
|
@@ -1393,11 +1417,11 @@ def portfolio_eset(pf_info,simulation=50000,convex_hull=False,frontier="both",fa
|
|
1393
1417
|
titletxt0=": Markowitz Feasible Set"
|
1394
1418
|
|
1395
1419
|
plt.colorbar(label='Return/Std')
|
1396
|
-
plt.title(pname+
|
1420
|
+
plt.title(pname+titletxt0,fontsize=title_txt_size)
|
1397
1421
|
plt.ylabel("Annualized Return",fontsize=ylabel_txt_size)
|
1398
1422
|
|
1399
1423
|
footnote1="Annualized Std -->\n\n"
|
1400
|
-
footnote2="
|
1424
|
+
footnote2="Built "+str(simulation)+" portfolios of given securities\n"
|
1401
1425
|
footnote3="Period of sample: "+hstart+" to "+hend
|
1402
1426
|
footnote4="\nData source: Sina/EM/Stooq/Yahoo, "+str(stoday)
|
1403
1427
|
|
@@ -1429,7 +1453,7 @@ def portfolio_es_sharpe(pf_info,simulation=50000,RF=0):
|
|
1429
1453
|
"""
|
1430
1454
|
功能:基于随机数,生成大量可能的投资组合,计算各个投资组合的年均风险溢价及其标准差,绘制投资组合的可行集
|
1431
1455
|
"""
|
1432
|
-
print(" Calculating
|
1456
|
+
print(f" Calculating {simulation} portfolio combinations ...")
|
1433
1457
|
|
1434
1458
|
[[portfolio,thedate,stock_return0,rf_df,_],_]=pf_info
|
1435
1459
|
pname=portfolio_name(portfolio)
|
@@ -1523,7 +1547,7 @@ def portfolio_es_sortino(pf_info,simulation=50000,RF=0):
|
|
1523
1547
|
"""
|
1524
1548
|
功能:基于随机数,生成大量可能的投资组合,计算各个投资组合的年均风险溢价及其下偏标准差,绘制投资组合的可行集
|
1525
1549
|
"""
|
1526
|
-
print(" Calculating
|
1550
|
+
print(f" Calculating {simulation} portfolio combinations ...")
|
1527
1551
|
|
1528
1552
|
[[portfolio,thedate,stock_return0,rf_df,_],_]=pf_info
|
1529
1553
|
pname=portfolio_name(portfolio)
|
@@ -1621,9 +1645,10 @@ if __name__=='__main__':
|
|
1621
1645
|
|
1622
1646
|
def portfolio_es_alpha(pf_info,simulation=50000,RF=0):
|
1623
1647
|
"""
|
1624
|
-
|
1648
|
+
功能:基于随机数,生成大量可能的投资组合,计算各个投资组合的年化标准差和阿尔法指数,
|
1649
|
+
绘制投资组合的可行集
|
1625
1650
|
"""
|
1626
|
-
print(" Calculating
|
1651
|
+
print(f" Calculating {simulation} portfolio combinations ...")
|
1627
1652
|
|
1628
1653
|
[[portfolio,thedate,stock_return0,rf_df,_],_]=pf_info
|
1629
1654
|
pname=portfolio_name(portfolio)
|
@@ -1636,7 +1661,18 @@ def portfolio_es_alpha(pf_info,simulation=50000,RF=0):
|
|
1636
1661
|
#计算市场指数的收益率
|
1637
1662
|
import pandas as pd
|
1638
1663
|
start1=date_adjust(hstart,adjust=-30)
|
1639
|
-
|
1664
|
+
|
1665
|
+
import os, sys
|
1666
|
+
class HiddenPrints:
|
1667
|
+
def __enter__(self):
|
1668
|
+
self._original_stdout = sys.stdout
|
1669
|
+
sys.stdout = open(os.devnull, 'w')
|
1670
|
+
|
1671
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
1672
|
+
sys.stdout.close()
|
1673
|
+
sys.stdout = self._original_stdout
|
1674
|
+
with HiddenPrints():
|
1675
|
+
mkt=get_prices(mktidx,start1,hend)
|
1640
1676
|
mkt['Mkt']=mkt['Close'].pct_change()
|
1641
1677
|
mkt.dropna(inplace=True)
|
1642
1678
|
mkt1=pd.DataFrame(mkt['Mkt'])
|
@@ -1741,7 +1777,7 @@ def portfolio_es_treynor(pf_info,simulation=50000,RF=0):
|
|
1741
1777
|
"""
|
1742
1778
|
功能:基于随机数,生成大量可能的投资组合,计算各个投资组合的风险溢价和贝塔系数,绘制投资组合的可行集
|
1743
1779
|
"""
|
1744
|
-
print(" Calculating
|
1780
|
+
print(f" Calculating {simulation} portfolio combinations ...")
|
1745
1781
|
|
1746
1782
|
[[portfolio,_,stock_return0,rf_df,_],_]=pf_info
|
1747
1783
|
pname=portfolio_name(portfolio)
|
@@ -1754,7 +1790,18 @@ def portfolio_es_treynor(pf_info,simulation=50000,RF=0):
|
|
1754
1790
|
#计算市场指数的收益率
|
1755
1791
|
import pandas as pd
|
1756
1792
|
start1=date_adjust(hstart,adjust=-30)
|
1757
|
-
|
1793
|
+
|
1794
|
+
import os, sys
|
1795
|
+
class HiddenPrints:
|
1796
|
+
def __enter__(self):
|
1797
|
+
self._original_stdout = sys.stdout
|
1798
|
+
sys.stdout = open(os.devnull, 'w')
|
1799
|
+
|
1800
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
1801
|
+
sys.stdout.close()
|
1802
|
+
sys.stdout = self._original_stdout
|
1803
|
+
with HiddenPrints():
|
1804
|
+
mkt=get_prices(mktidx,start1,hend)
|
1758
1805
|
mkt['Mkt']=mkt['Close'].pct_change()
|
1759
1806
|
mkt.dropna(inplace=True)
|
1760
1807
|
mkt1=pd.DataFrame(mkt['Mkt'])
|
@@ -1833,6 +1880,8 @@ def portfolio_es_treynor(pf_info,simulation=50000,RF=0):
|
|
1833
1880
|
# 设置数据框RandomPortfolios每一列的名称
|
1834
1881
|
RandomPortfolios.columns = [ticker + "_weight" for ticker in tickerlist] \
|
1835
1882
|
+ ['Risk premium', 'beta']
|
1883
|
+
# 新增
|
1884
|
+
RandomPortfolios['treynor']=RandomPortfolios['Risk premium']/RandomPortfolios['beta']
|
1836
1885
|
|
1837
1886
|
return [pf_info,RandomPortfolios]
|
1838
1887
|
|
@@ -1898,6 +1947,8 @@ def RandomPortfolios_plot(RandomPortfolios,col_x,col_y,colorbartxt,title_ext, \
|
|
1898
1947
|
pf_returns_list=list(pf_returns)
|
1899
1948
|
points=[]
|
1900
1949
|
for x in pf_volatilities_list:
|
1950
|
+
print_progress_percent2(x,pf_volatilities_list,steps=5,leading_blanks=4)
|
1951
|
+
|
1901
1952
|
pos=pf_volatilities_list.index(x)
|
1902
1953
|
y=pf_returns_list[pos]
|
1903
1954
|
points=points+[[x,y]]
|
@@ -1960,7 +2011,10 @@ def RandomPortfolios_plot(RandomPortfolios,col_x,col_y,colorbartxt,title_ext, \
|
|
1960
2011
|
pass
|
1961
2012
|
else:
|
1962
2013
|
#无convex hull
|
1963
|
-
|
2014
|
+
pass
|
2015
|
+
|
2016
|
+
# 空一行
|
2017
|
+
print('')
|
1964
2018
|
|
1965
2019
|
lang = check_language()
|
1966
2020
|
if lang == 'Chinese':
|
@@ -1982,7 +2036,7 @@ def RandomPortfolios_plot(RandomPortfolios,col_x,col_y,colorbartxt,title_ext, \
|
|
1982
2036
|
|
1983
2037
|
import datetime as dt; stoday=dt.date.today()
|
1984
2038
|
footnote1=x_axis_name+" -->\n\n"
|
1985
|
-
footnote2="
|
2039
|
+
footnote2="Built "+str(simulation)+" portfolios of given securities"
|
1986
2040
|
footnote3="\nPeriod of sample: "+hstart+" to "+hend
|
1987
2041
|
footnote4="\nData source: Sina/EM/Stooq/Yahoo, "+str(stoday)
|
1988
2042
|
|
@@ -2213,8 +2267,9 @@ def portfolio_optimize_alpha(es_info,graph=True,convex_hull=False,frontier='effi
|
|
2213
2267
|
"""
|
2214
2268
|
|
2215
2269
|
#需要定制:定义名称变量......................................................
|
2216
|
-
col_ratio='
|
2217
|
-
col_y='alpha'
|
2270
|
+
col_ratio='Alpha' #指数名称
|
2271
|
+
col_y='alpha' #指数分子
|
2272
|
+
#col_y='Risk premium' #指数分子
|
2218
2273
|
col_x='beta' #指数分母
|
2219
2274
|
|
2220
2275
|
name_hiret='MAR' #Maximum Alpha Ratio,指数最高点
|
@@ -2261,15 +2316,16 @@ def portfolio_optimize_treynor(es_info,graph=True,convex_hull=False,frontier='ef
|
|
2261
2316
|
|
2262
2317
|
#需要定制:定义名称变量......................................................
|
2263
2318
|
col_ratio='Treynor' #指数名称
|
2264
|
-
col_y='
|
2265
|
-
col_x='beta'
|
2319
|
+
col_y='treynor' #指数:直接做纵轴
|
2320
|
+
col_x='beta' #做横轴
|
2266
2321
|
|
2267
2322
|
name_hiret='MTR' #Maximum Treynor Ratio,指数最高点
|
2268
2323
|
name_lorisk='GMBT' #Global Minimum Beta in Treynor,风险最低点
|
2269
2324
|
|
2270
2325
|
title_ext=text_lang("特雷诺比率","Treynor Ratio") #用于标题区别
|
2271
2326
|
colorbartxt=text_lang("特雷诺比率","Treynor Ratio") #用于彩色棒标签
|
2272
|
-
ylabeltxt=text_lang("年化风险溢价","Annualized Risk Premium") #用于纵轴名称
|
2327
|
+
#ylabeltxt=text_lang("年化风险溢价","Annualized Risk Premium") #用于纵轴名称
|
2328
|
+
ylabeltxt=text_lang("特雷诺比率·","Treynor Ratio")
|
2273
2329
|
x_axis_name=text_lang("贝塔系数","Beta") #用于横轴名称
|
2274
2330
|
#定制部分结束...............................................................
|
2275
2331
|
|
@@ -2320,9 +2376,9 @@ def portfolio_optimize_rar(es_info,col_ratio,col_y,col_x,name_hiret,name_lorisk,
|
|
2320
2376
|
hend0=StockReturns.index[-1]; hend=str(hend0.strftime("%Y-%m-%d"))
|
2321
2377
|
|
2322
2378
|
#识别并计算指数..........................................................
|
2323
|
-
if col_ratio in ['Alpha']:
|
2379
|
+
if col_ratio.title() in ['Treynor','Alpha']:
|
2324
2380
|
RandomPortfolios[col_ratio] = RandomPortfolios[col_y]
|
2325
|
-
elif col_ratio in ['
|
2381
|
+
elif col_ratio.title() in ['Sharpe','Sortino']:
|
2326
2382
|
RandomPortfolios[col_ratio] = RandomPortfolios[col_y] / RandomPortfolios[col_x]
|
2327
2383
|
else:
|
2328
2384
|
print(" #Error(portfolio_optimize_rar): invalid rar",col_ratio)
|
@@ -2399,27 +2455,39 @@ if __name__=='__main__':
|
|
2399
2455
|
simulation=1000
|
2400
2456
|
simulation=50000
|
2401
2457
|
|
2402
|
-
|
2403
|
-
|
2404
|
-
|
2458
|
+
pf_info0=pf_info
|
2459
|
+
ratio='treynor'
|
2460
|
+
|
2461
|
+
simulation=10000
|
2462
|
+
RF=0.046
|
2463
|
+
graph=True
|
2464
|
+
hirar_return=True; lorisk=True
|
2465
|
+
convex_hull=True; frontier='efficient'; facecolor='papayawhip'
|
2466
|
+
|
2467
|
+
|
2405
2468
|
|
2406
|
-
def portfolio_optimize(
|
2469
|
+
def portfolio_optimize(pf_info0,ratio='sharpe',simulation=10000,RF=0, \
|
2407
2470
|
graph=True,hirar_return=False,lorisk=True, \
|
2408
2471
|
convex_hull=True,frontier='efficient',facecolor='papayawhip'):
|
2409
2472
|
"""
|
2410
2473
|
功能:集成式投资组合优化策略
|
2411
2474
|
注意:实验发现RF较小时对于结果的影响极其微小难以观察,默认设为不使用无风险利率调整收益
|
2412
|
-
|
2475
|
+
但RF较大时对于结果的影响明显变大,已经不能忽略!
|
2476
|
+
若可行集形状不佳,优先尝试pastyears=3,再尝试增加simulation次数。
|
2477
|
+
simulation数值过大时将导致速度太慢。
|
2413
2478
|
"""
|
2414
|
-
|
2479
|
+
# 防止原始数据被修改
|
2480
|
+
import copy
|
2481
|
+
pf_info=copy.deepcopy(pf_info0)
|
2415
2482
|
|
2416
2483
|
ratio_list=['treynor','sharpe','sortino','alpha']
|
2484
|
+
ratio=ratio.lower()
|
2417
2485
|
if not (ratio in ratio_list):
|
2418
2486
|
print(" #Error(portfolio_optimize_strategy): invalid strategy ratio",ratio)
|
2419
2487
|
print(" Supported strategy ratios",ratio_list)
|
2420
2488
|
return
|
2421
2489
|
|
2422
|
-
print(" Optimizing portfolio configuration
|
2490
|
+
print(" Optimizing portfolio configuration by",ratio,"ratio ...")
|
2423
2491
|
|
2424
2492
|
[[portfolio,_,_,_,_],_]=pf_info
|
2425
2493
|
pname=portfolio_name(portfolio)
|
@@ -2555,7 +2623,7 @@ def objFunction(W,R,target_ret):
|
|
2555
2623
|
def portfolio_ef_0(stocks,fromdate,todate):
|
2556
2624
|
"""
|
2557
2625
|
功能:绘制马科维茨有效前沿,不区分上半沿和下半沿
|
2558
|
-
|
2626
|
+
问题:很可能出现上下边界折叠的情况,难以解释,弃用!!!
|
2559
2627
|
"""
|
2560
2628
|
#Code for getting stock prices
|
2561
2629
|
prices=get_prices(stocks,fromdate,todate)
|
@@ -2630,7 +2698,7 @@ if __name__=='__main__':
|
|
2630
2698
|
def portfolio_ef(stocks,fromdate,todate):
|
2631
2699
|
"""
|
2632
2700
|
功能:多只股票的马科维茨有效边界,区分上半沿和下半沿,标记风险极小点
|
2633
|
-
|
2701
|
+
问题:很可能出现上下边界折叠的情况,难以解释,弃用!!!
|
2634
2702
|
"""
|
2635
2703
|
print("\n Searching for portfolio information, please wait...")
|
2636
2704
|
#Code for getting stock prices
|
@@ -2877,6 +2945,10 @@ def security_correlation(tickers,start='L5Y',end='today',info_type='Close', \
|
|
2877
2945
|
if __name__ =="__main__":
|
2878
2946
|
portfolio={'Market':('US','^GSPC','Test 1'),'EDU':0.4,'TAL':0.3,'TEDU':0.2}
|
2879
2947
|
|
2948
|
+
def portfolio_describe(portfolio):
|
2949
|
+
describe_portfolio(portfolio)
|
2950
|
+
return
|
2951
|
+
|
2880
2952
|
def describe_portfolio(portfolio):
|
2881
2953
|
"""
|
2882
2954
|
功能:描述投资组合的信息
|
@@ -2887,27 +2959,34 @@ def describe_portfolio(portfolio):
|
|
2887
2959
|
scope,mktidx,tickerlist,sharelist,ticker_type=decompose_portfolio(portfolio)
|
2888
2960
|
pname=portfolio_name(portfolio)
|
2889
2961
|
|
2890
|
-
print("***
|
2891
|
-
print("
|
2892
|
-
print("市场指数:",ticker_name(mktidx,'bond')+'('+mktidx+')')
|
2893
|
-
print("成分股及其份额:")
|
2962
|
+
print(text_lang("*** 投资组合名称:","*** Portfolio name:"),pname)
|
2963
|
+
print(text_lang("所在市场:","Market:"),ectranslate(scope))
|
2964
|
+
print(text_lang("市场指数:","Market index:"),ticker_name(mktidx,'bond')+'('+mktidx+')')
|
2965
|
+
print(text_lang("\n*** 成分股及其份额:","\n*** Members and shares:"))
|
2894
2966
|
|
2895
2967
|
num=len(tickerlist)
|
2896
2968
|
#seqlist=[]
|
2897
2969
|
tickerlist1=[]
|
2898
2970
|
sharelist1=[]
|
2971
|
+
totalshares=0
|
2899
2972
|
for t in range(num):
|
2900
2973
|
#seqlist=seqlist+[t+1]
|
2901
2974
|
tickerlist1=tickerlist1+[ticker_name(tickerlist[t],'bond')+'('+tickerlist[t]+')']
|
2902
|
-
sharelist1=sharelist1+[str(round(sharelist[t],2))+'%']
|
2975
|
+
sharelist1=sharelist1+[str(round(sharelist[t]*100,2))+'%']
|
2976
|
+
|
2977
|
+
totalshares=totalshares+sharelist[t]
|
2903
2978
|
|
2904
2979
|
import pandas as pd
|
2905
2980
|
#df=pd.DataFrame({'序号':seqlist,'成分股':tickerlist1,'份额':sharelist1})
|
2906
|
-
df=pd.DataFrame({'成分股':tickerlist1,'份额':sharelist1})
|
2981
|
+
df=pd.DataFrame({text_lang('成分股','Members'):tickerlist1,text_lang('份额','Shares'):sharelist1})
|
2907
2982
|
df.index=df.index+1
|
2908
2983
|
|
2909
2984
|
alignlist=['center','left','right']
|
2910
2985
|
print(df.to_markdown(index=True,tablefmt='plain',colalign=alignlist))
|
2986
|
+
|
2987
|
+
print("*** "+text_lang("成分股份额总和:","Total shares: ")+str(totalshares*100)+'%')
|
2988
|
+
if totalshares != 1:
|
2989
|
+
print(" #Warning: total shares is expecting to be 100%")
|
2911
2990
|
|
2912
2991
|
return
|
2913
2992
|
|
@@ -2941,6 +3020,128 @@ def portfolio_drop(portfolio,last=0,droplist=[],new_name=''):
|
|
2941
3020
|
|
2942
3021
|
return portfolio_new
|
2943
3022
|
|
3023
|
+
#==============================================================================
|
3024
|
+
def portfolio_define(name='My Portfolio', \
|
3025
|
+
market='CN', \
|
3026
|
+
market_index='000001.SS', \
|
3027
|
+
members={}, \
|
3028
|
+
check=False):
|
3029
|
+
"""
|
3030
|
+
功能:定义一个投资组合
|
3031
|
+
参数:
|
3032
|
+
name: 投资组合的名字
|
3033
|
+
economy_entity: 投资组合的成分股所在的经济体
|
3034
|
+
market_index: 经济体的代表性市场指数
|
3035
|
+
members: 数据字典,投资组合的各个成分股代码及其所占的股数份额
|
3036
|
+
|
3037
|
+
返回值:投资组合的字典型描述
|
3038
|
+
"""
|
3039
|
+
|
3040
|
+
# 检查市场名称
|
3041
|
+
market=market.upper()
|
3042
|
+
if len(market) != 2:
|
3043
|
+
print(" #Warning(portfolio_define): need a country code of 2 letters")
|
3044
|
+
return None
|
3045
|
+
|
3046
|
+
#屏蔽函数内print信息输出的类
|
3047
|
+
import os, sys
|
3048
|
+
class HiddenPrints:
|
3049
|
+
def __enter__(self):
|
3050
|
+
self._original_stdout = sys.stdout
|
3051
|
+
sys.stdout = open(os.devnull, 'w')
|
3052
|
+
|
3053
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
3054
|
+
sys.stdout.close()
|
3055
|
+
sys.stdout = self._original_stdout
|
3056
|
+
|
3057
|
+
error_flag=False
|
3058
|
+
govt_bond='1Y'+market+'Y.B'
|
3059
|
+
with HiddenPrints():
|
3060
|
+
rf_df=get_price_stooq(govt_bond,start='MRW')
|
3061
|
+
if not(rf_df is None):
|
3062
|
+
RF=round(rf_df['Close'].mean() / 100.0,6)
|
3063
|
+
print(f" Notice: recent annualized RF for {market} market is {RF} (or {round(RF*100,4)}%)")
|
3064
|
+
else:
|
3065
|
+
error_flag=True
|
3066
|
+
print(f" #Warning(portfolio_define): no RF info found for market {market}")
|
3067
|
+
print(" Solution: manually define annualized RF value without %")
|
3068
|
+
|
3069
|
+
# 检查是否存在成分股
|
3070
|
+
if not isinstance(members,dict):
|
3071
|
+
print(" #Warning(portfolio_define): invalid structure for portfolio members")
|
3072
|
+
return None
|
3073
|
+
|
3074
|
+
if len(members) == 0:
|
3075
|
+
print(" #Warning(portfolio_define): no members found in the portfolio")
|
3076
|
+
return None
|
3077
|
+
|
3078
|
+
try:
|
3079
|
+
keys=members.keys()
|
3080
|
+
values=members.values()
|
3081
|
+
except:
|
3082
|
+
print(" #Warning(portfolio_define): invalid dict for portfolio members")
|
3083
|
+
return None
|
3084
|
+
if len(keys) != len(values):
|
3085
|
+
print(" #Warning(portfolio_define): number of members and their portions mismatch")
|
3086
|
+
return None
|
3087
|
+
|
3088
|
+
marketdict={'Market':(market,market_index,name)}
|
3089
|
+
portfolio=dict(marketdict,**members)
|
3090
|
+
|
3091
|
+
if check:
|
3092
|
+
print(" Checking portfolio information ...")
|
3093
|
+
df=None
|
3094
|
+
with HiddenPrints():
|
3095
|
+
df=security_indicator(market_index,fromdate='MRW',graph=False)
|
3096
|
+
if df is None:
|
3097
|
+
error_flag=True
|
3098
|
+
print(f" #Warning(portfolio_define): market index {market_index} not found")
|
3099
|
+
|
3100
|
+
for t in keys:
|
3101
|
+
with HiddenPrints():
|
3102
|
+
df=security_indicator(t,fromdate='MRW',graph=False)
|
3103
|
+
if df is None:
|
3104
|
+
error_flag=True
|
3105
|
+
print(f" #Warning(portfolio_define): portfolio member {t} not found")
|
3106
|
+
|
3107
|
+
if not check:
|
3108
|
+
print(f" Notice: portfolio information not fully checked")
|
3109
|
+
else:
|
3110
|
+
if not error_flag:
|
3111
|
+
print(f" Congratulations! Portfolio is ready to go")
|
3112
|
+
else:
|
3113
|
+
print(f" #Warning(portfolio_define): there are issues in portfolio definition")
|
3114
|
+
|
3115
|
+
return portfolio,RF
|
3116
|
+
|
3117
|
+
|
3118
|
+
#==============================================================================
|
3119
|
+
|
3120
|
+
def portfolio_feasible(pf_info,simulation=10000,facecolor='papayawhip'):
|
3121
|
+
"""
|
3122
|
+
功能:绘制投资组合的可行集散点图,仅供教学演示,无实际用途
|
3123
|
+
"""
|
3124
|
+
fset=portfolio_feset(pf_info,frontier=None, \
|
3125
|
+
simulation=simulation,facecolor=facecolor)
|
3126
|
+
return
|
3127
|
+
#==============================================================================
|
3128
|
+
|
3129
|
+
def portfolio_efficient(pf_info,frontier='Both',simulation=10000,facecolor='papayawhip'):
|
3130
|
+
"""
|
3131
|
+
功能:绘制投资组合的有效边界散点图,仅供教学演示,无实际用途
|
3132
|
+
"""
|
3133
|
+
frontier=frontier.title()
|
3134
|
+
frontier_list=['Efficient','Inefficient','Both']
|
3135
|
+
if not (frontier in frontier_list):
|
3136
|
+
print(f" #Warning: invalid frontier {frontier}")
|
3137
|
+
print(f" Valid options for frontier: {frontier_list}")
|
3138
|
+
return
|
3139
|
+
|
3140
|
+
eset=portfolio_feset(pf_info,frontier=frontier, \
|
3141
|
+
simulation=simulation,facecolor=facecolor)
|
3142
|
+
|
3143
|
+
return
|
3144
|
+
|
2944
3145
|
#==============================================================================
|
2945
3146
|
#==============================================================================
|
2946
3147
|
#==============================================================================
|