siat 2.13.43__py3-none-any.whl → 2.14.2__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.
siat/security_prices.py CHANGED
@@ -53,7 +53,11 @@ def upper_ticker(ticker):
53
53
  elif isinstance(ticker,list):
54
54
  tlist=[]
55
55
  for t in ticker:
56
- tlist=tlist+[t.upper()]
56
+ try:
57
+ tupper=t.upper()
58
+ except:
59
+ tupper=t
60
+ tlist=tlist+[tupper]
57
61
  return tlist
58
62
 
59
63
  if __name__=='__main__':
@@ -988,8 +992,10 @@ if __name__=='__main__':
988
992
 
989
993
  if __name__=='__main__':
990
994
  ticker='AAPL'
991
- start='2020-12-1'
992
- end='2021-1-31'
995
+ ticker='^JN0U.JO'
996
+
997
+ start='2023-12-1'
998
+ end='2024-3-31'
993
999
  retry_count=3
994
1000
  pause=1
995
1001
 
@@ -1235,28 +1241,38 @@ def create_tuple_for_columns(df_a, multi_level_col):
1235
1241
  #==============================================================================
1236
1242
  #==============================================================================
1237
1243
  #==============================================================================
1238
- def get_price_portfolio(tickerlist,sharelist,fromdate,todate,adj=False):
1244
+ def get_price_portfolio(tickerlist,sharelist,fromdate,todate,adj=False,source='auto'):
1239
1245
  """
1240
1246
  套壳函数get_prices_portfolio
1247
+ 经测试,已经能够支持capm_beta2
1241
1248
  """
1242
- df=get_prices_portfolio(tickerlist,sharelist,fromdate,todate,adj=adj)
1249
+ df=get_prices_portfolio(tickerlist,sharelist,fromdate,todate,adj=adj,source=source)
1243
1250
  return df
1244
1251
 
1245
1252
  if __name__=='__main__':
1246
1253
  tickerlist=['INTC','MSFT']
1247
1254
  sharelist=[0.6,0.4]
1248
1255
 
1256
+ tickerlist=['600519.SS', '000858.SZ', '600809.SS']
1257
+ sharelist=[0.4,0.3,0.3]
1258
+
1249
1259
  tickerlist=['JD']
1250
1260
  sharelist=[1000]
1251
1261
 
1252
1262
  tickerlist=['601988.SS']
1253
1263
  sharelist=[1000]
1254
1264
 
1255
- fromdate='2023-1-1'
1256
- todate='2023-3-8'
1265
+ fromdate='2024-1-1'
1266
+ todate='2024-3-23'
1257
1267
  adj=False
1268
+ source='auto'
1269
+
1270
+ security={'Market':('US','^SPX','中概教培组合'),'EDU':0.4,'TAL':0.3,'TCTM':0.2}
1271
+ _,_,tickerlist,sharelist=decompose_portfolio(security)
1272
+
1273
+ p=get_prices_portfolio(tickerlist,sharelist,fromdate,todate,source='auto')
1258
1274
 
1259
- def get_prices_portfolio(tickerlist,sharelist,fromdate,todate,adj=False):
1275
+ def get_prices_portfolio(tickerlist,sharelist,fromdate,todate,adj=False,source='auto'):
1260
1276
  """
1261
1277
  功能:抓取投资组合的每日价值
1262
1278
  输入:股票代码列表,份额列表,开始日期,结束日期
@@ -1267,6 +1283,7 @@ def get_prices_portfolio(tickerlist,sharelist,fromdate,todate,adj=False):
1267
1283
 
1268
1284
  输出:投资组合的价格序列,按照日期升序排列
1269
1285
  """
1286
+ import pandas as pd
1270
1287
 
1271
1288
  #检查股票列表个数与份额列表个数是否一致
1272
1289
  if len(tickerlist) != len(sharelist):
@@ -1274,9 +1291,14 @@ def get_prices_portfolio(tickerlist,sharelist,fromdate,todate,adj=False):
1274
1291
  return None
1275
1292
 
1276
1293
  #抓取股票价格
1277
- p=get_prices(tickerlist,fromdate,todate,adj=adj)
1294
+ p=get_prices(tickerlist,fromdate,todate,adj=adj,source=source)
1278
1295
  if p is None: return None
1279
1296
 
1297
+ #删除无用的空列preclose,避免引起后续程序误判
1298
+ try:
1299
+ del p['prevclose']
1300
+ except: pass
1301
+
1280
1302
  #结果非空时,检查整列为空的证券代码
1281
1303
  nancollist=[]
1282
1304
  collist=list(p)
@@ -1298,10 +1320,12 @@ def get_prices_portfolio(tickerlist,sharelist,fromdate,todate,adj=False):
1298
1320
  #删除投资组合中相关的权重
1299
1321
  for w in wrongtickers:
1300
1322
  pos=tickerlist.index(w)
1301
- del sharelist[pos]
1323
+ try:
1324
+ del tickerlist[pos]
1325
+ del sharelist[pos]
1326
+ except: pass
1302
1327
 
1303
1328
  if len(sharelist) > 1:
1304
- import pandas as pd
1305
1329
  #计算投资者的开盘价
1306
1330
  op=p['Open']
1307
1331
  #计算投资组合的价值
@@ -1341,12 +1365,15 @@ def get_prices_portfolio(tickerlist,sharelist,fromdate,todate,adj=False):
1341
1365
 
1342
1366
  prices['Portfolio']=str(tickerlist)
1343
1367
  prices['Shares']=str(sharelist)
1344
- prices['Adjustment']=prices.apply(lambda x: \
1345
- False if x['Close']==x['Adj Close'] else True, axis=1)
1346
-
1347
- stockdf=prices[['Portfolio','Shares','Date','Weekday', \
1348
- 'Open','Close','Adj Close','Adjustment']]
1349
-
1368
+ try:
1369
+ prices['Adjustment']=prices.apply(lambda x: \
1370
+ False if x['Close']==x['Adj Close'] else True, axis=1)
1371
+
1372
+ stockdf=prices[['Portfolio','Shares','Date','Weekday', \
1373
+ 'Open','Close','Adj Close','Adjustment']]
1374
+ except:
1375
+ return None
1376
+
1350
1377
  return stockdf
1351
1378
 
1352
1379
  if __name__=='__main__':
@@ -1614,11 +1641,13 @@ def rolling_price_volatility(df, period="Weekly"):
1614
1641
  #计算滚动期间的调整标准差价格风险:基于收盘价
1615
1642
  retname1=period+" Price Volatility"
1616
1643
  import numpy as np
1617
- df[retname1]=df["Close"].rolling(rollingnum).apply(lambda x: np.std(x,ddof=1)/np.mean(x)*np.sqrt(len(x)))
1644
+ #df[retname1]=df["Close"].rolling(rollingnum).apply(lambda x: np.std(x,ddof=1)/np.mean(x)*np.sqrt(len(x)))
1645
+ df[retname1]=df["Close"].rolling(rollingnum).apply(lambda x: np.std(x,ddof=1)/np.mean(x))
1618
1646
 
1619
1647
  #计算滚动期间的调整标准差价格风险:基于调整收盘价
1620
1648
  retname3=period+" Adj Price Volatility"
1621
- df[retname3]=df["Adj Close"].rolling(rollingnum).apply(lambda x: np.std(x,ddof=1)/np.mean(x)*np.sqrt(len(x)))
1649
+ #df[retname3]=df["Adj Close"].rolling(rollingnum).apply(lambda x: np.std(x,ddof=1)/np.mean(x)*np.sqrt(len(x)))
1650
+ df[retname3]=df["Adj Close"].rolling(rollingnum).apply(lambda x: np.std(x,ddof=1)/np.mean(x))
1622
1651
 
1623
1652
  return df
1624
1653
 
@@ -1642,11 +1671,13 @@ def expanding_price_volatility(df0,basedate):
1642
1671
  #计算扩展窗口调整价格风险:基于收盘价
1643
1672
  retname1="Exp Price Volatility"
1644
1673
  import numpy as np
1645
- df[retname1]=df["Close"].expanding(min_periods=1).apply(lambda x: np.std(x,ddof=1)/np.mean(x)*np.sqrt(len(x)))
1674
+ #df[retname1]=df["Close"].expanding(min_periods=1).apply(lambda x: np.std(x,ddof=1)/np.mean(x)*np.sqrt(len(x)))
1675
+ df[retname1]=df["Close"].expanding(min_periods=1).apply(lambda x: np.std(x,ddof=1)/np.mean(x))
1646
1676
 
1647
1677
  #计算扩展窗口调整价格风险:基于调整收盘价
1648
1678
  retname3="Exp Adj Price Volatility"
1649
- df[retname3]=df["Adj Close"].expanding(min_periods=1).apply(lambda x: np.std(x,ddof=1)/np.mean(x)*np.sqrt(len(x)))
1679
+ #df[retname3]=df["Adj Close"].expanding(min_periods=1).apply(lambda x: np.std(x,ddof=1)/np.mean(x)*np.sqrt(len(x)))
1680
+ df[retname3]=df["Adj Close"].expanding(min_periods=1).apply(lambda x: np.std(x,ddof=1)/np.mean(x))
1650
1681
 
1651
1682
  return df
1652
1683
 
@@ -1717,13 +1748,15 @@ def expanding_ret_volatility(df0,basedate):
1717
1748
  retname2="Exp Ret Volatility%"
1718
1749
  import numpy as np
1719
1750
 
1720
- df[retname1]=df["Daily Ret"].expanding(min_periods=1).apply(lambda x: np.std(x,ddof=1)*np.sqrt(len(x)))
1751
+ #df[retname1]=df["Daily Ret"].expanding(min_periods=1).apply(lambda x: np.std(x,ddof=1)*np.sqrt(len(x)))
1752
+ df[retname1]=df["Daily Ret"].expanding(min_periods=1).apply(lambda x: np.std(x,ddof=1))
1721
1753
  df[retname2]=df[retname1]*100.0
1722
1754
 
1723
1755
  #计算扩展窗口调整收益率风险:基于调整收益率
1724
1756
  retname3="Exp Adj Ret Volatility"
1725
1757
  retname4="Exp Adj Ret Volatility%"
1726
- df[retname3]=df["Daily Adj Ret"].expanding(min_periods=1).apply(lambda x: np.std(x,ddof=1)*np.sqrt(len(x)))
1758
+ #df[retname3]=df["Daily Adj Ret"].expanding(min_periods=1).apply(lambda x: np.std(x,ddof=1)*np.sqrt(len(x)))
1759
+ df[retname3]=df["Daily Adj Ret"].expanding(min_periods=1).apply(lambda x: np.std(x,ddof=1))
1727
1760
  df[retname4]=df[retname3]*100.0
1728
1761
 
1729
1762
  return df
@@ -1830,13 +1863,15 @@ def expanding_ret_lpsd(df0,basedate):
1830
1863
  retname1="Exp Ret LPSD"
1831
1864
  retname2=retname1+'%'
1832
1865
  import numpy as np
1833
- df[retname1]=df["Daily Ret"].expanding(min_periods=1).apply(lambda x: lpsd(x)*np.sqrt(len(x)))
1866
+ #df[retname1]=df["Daily Ret"].expanding(min_periods=1).apply(lambda x: lpsd(x)*np.sqrt(len(x)))
1867
+ df[retname1]=df["Daily Ret"].expanding(min_periods=1).apply(lambda x: lpsd(x))
1834
1868
  df[retname2]=df[retname1]*100.0
1835
1869
 
1836
1870
  #计算扩展窗口调整下偏标准差:基于调整收益率
1837
1871
  retname3="Exp Adj Ret LPSD"
1838
1872
  retname4=retname3+'%'
1839
- df[retname3]=df["Daily Adj Ret"].expanding(min_periods=1).apply(lambda x: lpsd(x)*np.sqrt(len(x)))
1873
+ #df[retname3]=df["Daily Adj Ret"].expanding(min_periods=1).apply(lambda x: lpsd(x)*np.sqrt(len(x)))
1874
+ df[retname3]=df["Daily Adj Ret"].expanding(min_periods=1).apply(lambda x: lpsd(x))
1840
1875
  df[retname4]=df[retname3]*100.0
1841
1876
 
1842
1877
  return df
@@ -2044,7 +2079,7 @@ def recent_stock_split(ticker):
2044
2079
 
2045
2080
  import datetime
2046
2081
  today = datetime.date.today()
2047
- print("数据来源: 新浪/stooq,",today)
2082
+ print("数据来源: 综合新浪/yahoo,",today)
2048
2083
 
2049
2084
  return divdf
2050
2085
 
@@ -2096,6 +2131,48 @@ def get_last_close(ticker):
2096
2131
  if __name__ =="__main__":
2097
2132
  get_last_close('AAPL')
2098
2133
 
2134
+ #==============================================================================
2135
+
2136
+ if __name__=='__main__':
2137
+ security={'Market':('US','^SPX','中概教培组合'),'EDU':0.4,'TAL':0.3,'TCTM':0.2}
2138
+ security={'Market':('US','^SPX','China Edtraining'),'X01':0.4,'X02':0.3,'X03':0.2}
2139
+ security={'Market':('China','000300.SS','China Edtraining'),'600519.SS':0.4,'000858.SZ':0.3,'600809.SS':0.2}
2140
+ security={'Market':('China','auto','China Edtraining'),'600519.SS':0.4,'000858.SZ':0.3,'600809.SS':0.2}
2141
+ security='600519.SS'
2142
+
2143
+ start='2024-1-1'; end='2024-3-23'
2144
+ source='auto'
2145
+
2146
+ prices=get_price_security(security,start,end)
2147
+
2148
+ def get_price_security(security,start,end,source='auto'):
2149
+ """
2150
+ 功能:获取股票或投资组合的价格
2151
+ 经测试已经可以支持capm_beta2,risk_adjusted_return待测试?
2152
+ """
2153
+
2154
+ if isinstance(security,dict): #投资组合
2155
+ scope,mktidx,tickerlist,sharelist=decompose_portfolio(security)
2156
+ prices=get_price_portfolio(tickerlist,sharelist,start,end,source=source)
2157
+
2158
+ pname=portfolio_name(security)
2159
+ if prices is None:
2160
+ print(" #Error(get_price_security): no price info retrieved for portfolio",pname)
2161
+ return None
2162
+ if len(prices) ==0:
2163
+ print(" #Error(get_price_security): zero info retrieved for portfolio",pname)
2164
+ return None
2165
+ else: #股票或股票列表
2166
+ prices=get_price(security,start,end,source=source)
2167
+ if prices is None:
2168
+ print(" #Error(get_price_security): no price info retrieved for",security)
2169
+ return None
2170
+ if len(prices) ==0:
2171
+ print(" #Error(get_price_security): zero info retrieved for",security)
2172
+ return None
2173
+
2174
+ return prices
2175
+
2099
2176
  #==============================================================================
2100
2177
  #==============================================================================
2101
2178
  #==============================================================================
siat/security_trend.py CHANGED
@@ -94,8 +94,12 @@ def security_trend(ticker,indicator='Close', \
94
94
  source='auto'):
95
95
 
96
96
  """
97
- 国内:描述证券指标走势
97
+ 功能:描述证券指标走势
98
+ 指标种类:默认为收盘价,包括收益率指标、风险指标、RAR指标、估值指标。
99
+ 窗口:滚动窗口,扩展窗口。
100
+ 数量变换:多种,默认不变换,常用的为scaling。
98
101
 
102
+ 注意:base='Annual Ret%'需要与window=252一致,如果不一致,以base为准。
99
103
  """
100
104
 
101
105
  # 检查证券代码
@@ -162,7 +166,7 @@ def security_trend(ticker,indicator='Close', \
162
166
  print(" #Warning(security_trend): invalid window size, reset to annual")
163
167
  window=252
164
168
 
165
- # 处理K线图
169
+ # 处理K线图=================================================================
166
170
  if kline and not kline_demo:
167
171
  # 跟踪
168
172
  #print(tickers[0],fromdate,todate)
@@ -180,7 +184,7 @@ def security_trend(ticker,indicator='Close', \
180
184
  df=candlestick_demo(tickers[0],fromdate=fromdate,todate=todate)
181
185
  return df
182
186
 
183
- # 处理股票分红和股票分拆:需要访问雅虎财经
187
+ # 处理股票分红和股票分拆:需要访问雅虎财经=====================================
184
188
  if stock_dividend:
185
189
  if start in ['default']:
186
190
  fromdate=date_adjust(todate,adjust=-365*5)
@@ -196,7 +200,7 @@ def security_trend(ticker,indicator='Close', \
196
200
  return df
197
201
 
198
202
 
199
- # 检查指标:是否字符串或列表
203
+ # 检查指标:是否字符串或列表=================================================
200
204
  if isinstance(indicator,str):
201
205
  measures=[indicator]
202
206
  indicator_num=1
@@ -251,7 +255,7 @@ def security_trend(ticker,indicator='Close', \
251
255
  printlist(indicator_list3,numperline=5,beforehand=' ',separator=' ')
252
256
  return None
253
257
 
254
- # 不能同时支持indicator_list1、indicator_list2和indicator_list3的指标,即不能跨组比较
258
+ # 不能同时支持indicator_list1、indicator_list2和indicator_list3的指标,即不能跨组比较!
255
259
  indicator_group1=False
256
260
  indicator_group2=False
257
261
  indicator_group3=False
@@ -278,7 +282,7 @@ def security_trend(ticker,indicator='Close', \
278
282
  print(" #Error(security_trend): cannot support in different indicator groups together for",measures)
279
283
  return None
280
284
 
281
- # 情形1:单个证券,单个普通指标
285
+ # 情形1:单个证券,单个普通指标===============================================
282
286
  # 绘制横线
283
287
  zeroline=False
284
288
  if (critical_value != ''):
@@ -294,14 +298,14 @@ def security_trend(ticker,indicator='Close', \
294
298
  source=source)
295
299
  return df
296
300
 
297
- # 情形2:单个证券,两个普通指标,twinx==True
301
+ # 情形2:单个证券,两个普通指标,twinx==True =================================
298
302
  if ticker_num==1 and indicator_num == 2 and indicator_group1 and twinx:
299
303
  df=compare_security(tickers=tickers[0],measures=measures[:2], \
300
304
  fromdate=fromdate,todate=todate,twinx=twinx, \
301
305
  loc1=loc1,loc2=loc2,graph=graph,source=source)
302
306
  return df
303
307
 
304
- # 情形3:单个证券,两个及以上普通指标
308
+ # 情形3:单个证券,两个及以上普通指标=========================================
305
309
  if ticker_num==1 and indicator_num >= 2 and indicator_group1 and not twinx:
306
310
  df=security_mindicators(ticker=tickers[0],measures=measures, \
307
311
  fromdate=fromdate,todate=todate, \
@@ -311,14 +315,14 @@ def security_trend(ticker,indicator='Close', \
311
315
  source=source)
312
316
  return df
313
317
 
314
- # 情形4:两个证券,取第一个普通指标,twinx==True
318
+ # 情形4:两个证券,取第一个普通指标,twinx==True =============================
315
319
  if ticker_num==2 and indicator_group1 and twinx:
316
320
  df=compare_security(tickers=tickers,measures=measures[0], \
317
321
  fromdate=fromdate,todate=todate,twinx=twinx, \
318
322
  loc1=loc1,loc2=loc2,graph=graph,source=source)
319
323
  return df
320
324
 
321
- # 情形5:两个及以上证券,取第一个普通指标
325
+ # 情形5:两个及以上证券,取第一个普通指标=====================================
322
326
  if ticker_num==2:
323
327
  linewidth=2.5
324
328
  elif ticker_num==3:
@@ -345,7 +349,7 @@ def security_trend(ticker,indicator='Close', \
345
349
  source=source)
346
350
  return df
347
351
 
348
- # 情形6:单个证券,单个或多个RAR指标
352
+ # 情形6:单个证券,单个或多个RAR指标=========================================
349
353
  # 特别注意:与收益率对比时若使用扩展收益率可能导致矛盾,要使用滚动收益率
350
354
  if indicator_group2 and ticker_num==1 and indicator_num >= 1:
351
355
  df=compare_1security_mrar(ticker=tickers[0],rar_names=measures, \
@@ -356,7 +360,7 @@ def security_trend(ticker,indicator='Close', \
356
360
  annotate=annotate)
357
361
  return df
358
362
 
359
- # 情形7:多个证券,取第一个RAR指标
363
+ # 情形7:多个证券,取第一个RAR指标===========================================
360
364
  # 特别注意:与收益率对比时若使用扩展收益率可能导致矛盾,要使用滚动收益率
361
365
  if indicator_group2 and ticker_num > 1:
362
366
  df=compare_mrar(tickers=tickers,rar_name=measures[0], \
@@ -367,19 +371,20 @@ def security_trend(ticker,indicator='Close', \
367
371
  annotate=annotate)
368
372
  return df
369
373
 
370
- # 情形8:估值指标PE/PB/MV/ROE
374
+ # 情形8:估值指标PE/PB/MV/ROE===============================================
371
375
  if indicator_group3:
372
376
  df=security_valuation(tickers=tickers,indicators=measures,start=fromdate,end=todate, \
373
377
  preprocess=preprocess,scaling_option=scaling_option, \
374
378
  twinx=twinx,loc1=loc1,loc2=loc2, \
375
- graph=graph,annotate=annotate,
376
- )
379
+ graph=graph,annotate=annotate)
377
380
  return df
378
381
 
379
382
  # 其他未预料情形
380
383
  print(" Sorry, unsupported combination of security(ies) and indicator(s):-(")
381
384
  return None
382
385
 
386
+ #==============================================================================
387
+
383
388
  #==============================================================================
384
389
  #==============================================================================
385
390
  #==============================================================================