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/allin.py +4 -1
- siat/bond_zh_sina.py +143 -0
- siat/capm_beta2.py +615 -0
- siat/common.py +758 -31
- siat/grafix.py +211 -89
- siat/risk_adjusted_return.py +5 -5
- siat/risk_adjusted_return2.py +1339 -0
- siat/security_prices.py +103 -26
- siat/security_trend.py +20 -15
- siat/security_trend2.py +486 -0
- siat/stock.py +34 -16
- siat/stock_technical.py +21 -49
- siat/translate.py +30 -4
- {siat-2.13.43.dist-info → siat-2.14.2.dist-info}/METADATA +1 -1
- {siat-2.13.43.dist-info → siat-2.14.2.dist-info}/RECORD +17 -13
- {siat-2.13.43.dist-info → siat-2.14.2.dist-info}/WHEEL +0 -0
- {siat-2.13.43.dist-info → siat-2.14.2.dist-info}/top_level.txt +0 -0
siat/common.py
CHANGED
@@ -284,6 +284,12 @@ def calculate_days(start_date, end_date):
|
|
284
284
|
|
285
285
|
|
286
286
|
#==============================================================================
|
287
|
+
if __name__ =="__main__":
|
288
|
+
basedate='2020-3-17'
|
289
|
+
adjust=-365
|
290
|
+
newdate = date_adjust(basedate, adjust)
|
291
|
+
print(newdate)
|
292
|
+
|
287
293
|
def date_adjust(basedate, adjust=0):
|
288
294
|
"""
|
289
295
|
功能:将给定日期向前或向后调整特定的天数
|
@@ -309,11 +315,105 @@ def date_adjust(basedate, adjust=0):
|
|
309
315
|
return str(newdate)
|
310
316
|
|
311
317
|
if __name__ =="__main__":
|
312
|
-
basedate='
|
313
|
-
|
314
|
-
|
315
|
-
|
318
|
+
basedate='2024-3-17'
|
319
|
+
|
320
|
+
adjust_year=-1; adjust_month=-1; adjust_day=-1
|
321
|
+
adjust_year=-1; adjust_month=-1; adjust_day=-17
|
322
|
+
adjust_year=-1; adjust_month=0; adjust_day=-17
|
323
|
+
adjust_year=0; adjust_month=-3; adjust_day=0
|
324
|
+
adjust_year=0; adjust_month=-13; adjust_day=0
|
325
|
+
adjust_year=0; adjust_month=-15; adjust_day=0
|
326
|
+
adjust_year=0; adjust_month=-27; adjust_day=0
|
327
|
+
adjust_year=0; adjust_month=-27; adjust_day=0
|
328
|
+
|
329
|
+
adjust_year=0; adjust_month=0; adjust_day=15
|
330
|
+
adjust_year=0; adjust_month=10; adjust_day=0
|
331
|
+
adjust_year=0; adjust_month=22; adjust_day=0
|
332
|
+
|
333
|
+
adjust_year=0; adjust_month=-1; adjust_day=-1
|
334
|
+
adjust_year=0; adjust_month=-2; adjust_day=-1
|
335
|
+
adjust_year=0; adjust_month=-3; adjust_day=-1
|
336
|
+
adjust_year=0; adjust_month=-6; adjust_day=-1
|
337
|
+
adjust_year=-1; adjust_month=0; adjust_day=0
|
338
|
+
adjust_year=-2; adjust_month=0; adjust_day=0
|
339
|
+
adjust_year=-3; adjust_month=0; adjust_day=0
|
340
|
+
adjust_year=-5; adjust_month=0; adjust_day=0
|
341
|
+
|
342
|
+
to_prev_month_end=False
|
343
|
+
to_prev_month_end=True
|
344
|
+
|
345
|
+
to_prev_year_end=False
|
346
|
+
to_prev_year_end=True
|
347
|
+
|
348
|
+
date_adjust2(basedate,adjust_year,adjust_month,adjust_day,to_prev_month_end,to_prev_year_end)
|
349
|
+
|
350
|
+
def date_adjust2(basedate,adjust_year=0,adjust_month=0,adjust_day=0, \
|
351
|
+
to_prev_month_end=False,to_prev_year_end=False):
|
352
|
+
"""
|
353
|
+
功能:将给定日期向前或向后调整特定的天数,按照年月日精确调整
|
354
|
+
输入:基础日期,需要调整的天数。
|
355
|
+
basedate: 基础日期。
|
356
|
+
adjust_year, adjust_month, adjust_day:分别调整的年月日数量,负数向前调整,正数向后调整。
|
357
|
+
输出:调整后的日期字符串。
|
358
|
+
"""
|
359
|
+
import pandas as pd
|
360
|
+
from datetime import datetime, timedelta
|
361
|
+
|
362
|
+
#检查基础日期的合理性
|
363
|
+
try:
|
364
|
+
bd=pd.to_datetime(basedate)
|
365
|
+
except:
|
366
|
+
print(" #Error(date_adjust2): invalid date",basedate)
|
367
|
+
return None
|
316
368
|
|
369
|
+
#将基础日期分解为年月日
|
370
|
+
bd_year=bd.year
|
371
|
+
bd_month=bd.month
|
372
|
+
bd_day=bd.day
|
373
|
+
|
374
|
+
#预处理调整的月数
|
375
|
+
if adjust_month <= -12:
|
376
|
+
adjust_year=adjust_year + int(adjust_month / 12)
|
377
|
+
adjust_month=adjust_month % -12
|
378
|
+
if adjust_month >= 12:
|
379
|
+
adjust_year=adjust_year + int(adjust_month / 12)
|
380
|
+
adjust_month=adjust_month % 12
|
381
|
+
|
382
|
+
#调整年
|
383
|
+
new_year=bd_year + adjust_year
|
384
|
+
|
385
|
+
#调整月份
|
386
|
+
new_month=bd_month + adjust_month
|
387
|
+
if new_month <= 0:
|
388
|
+
new_month=new_month + 12
|
389
|
+
new_year=new_year - 1
|
390
|
+
if new_month > 12:
|
391
|
+
new_month=new_month % 12
|
392
|
+
new_year=new_year + 1
|
393
|
+
|
394
|
+
#合成中间日期:新年份,新月份,原日期
|
395
|
+
ndym=datetime(new_year,new_month,bd_day)
|
396
|
+
|
397
|
+
#调整日期
|
398
|
+
nd=ndym + timedelta(days=adjust_day)
|
399
|
+
|
400
|
+
#如果还需要调整到上年年末,但不可同时使用调整到上月月末
|
401
|
+
if to_prev_year_end:
|
402
|
+
to_prev_month_end=False
|
403
|
+
|
404
|
+
nd_year=nd.year - 1
|
405
|
+
nd=datetime(nd_year,12,31)
|
406
|
+
|
407
|
+
#如果还需要调整到上月月末
|
408
|
+
if to_prev_month_end:
|
409
|
+
nd_day=nd.day
|
410
|
+
nd=nd + timedelta(days=-nd_day)
|
411
|
+
|
412
|
+
#提取日期字符串
|
413
|
+
newdate=nd.date()
|
414
|
+
|
415
|
+
return str(newdate)
|
416
|
+
|
317
417
|
#==============================================================================
|
318
418
|
if __name__ =="__main__":
|
319
419
|
portfolio={'Market':('US','^GSPC'),'EDU':0.4,'TAL':0.3,'TEDU':0.2}
|
@@ -357,13 +457,35 @@ def portfolio_name(portfolio):
|
|
357
457
|
try:
|
358
458
|
name=portfolio[keylist[0]][2]
|
359
459
|
except:
|
360
|
-
name="
|
460
|
+
name="PF1"
|
361
461
|
|
362
462
|
return name
|
363
463
|
|
364
464
|
if __name__=='__main__':
|
365
465
|
portfolio={'Market':('US','^GSPC','我的组合001'),'EDU':0.4,'TAL':0.3,'TEDU':0.2}
|
366
466
|
portfolio_name(portfolio)
|
467
|
+
|
468
|
+
if __name__=='__main__':
|
469
|
+
portfolio={'Market':('US','^GSPC','China Edtraining'),'EDU':0.4,'TAL':0.3,'TEDU':0.2}
|
470
|
+
portfolio='600519.SS'
|
471
|
+
|
472
|
+
isinstance_portfolio(portfolio)
|
473
|
+
|
474
|
+
def isinstance_portfolio(portfolio):
|
475
|
+
"""
|
476
|
+
功能:判断是否投资组合
|
477
|
+
输入:投资组合
|
478
|
+
输出:True, False
|
479
|
+
注意:为了维持兼容性,特此定义此函数
|
480
|
+
"""
|
481
|
+
result=True
|
482
|
+
|
483
|
+
try:
|
484
|
+
scope,mktidx,tickerlist,sharelist=decompose_portfolio(portfolio)
|
485
|
+
except:
|
486
|
+
result=False
|
487
|
+
|
488
|
+
return result
|
367
489
|
|
368
490
|
#==============================================================================
|
369
491
|
def calc_monthly_date_range(start,end):
|
@@ -598,19 +720,20 @@ def save_to_excel(df,filedir,excelfile,sheetname="Sheet1"):
|
|
598
720
|
注意:如果df中含有以文本表示的数字,写入到Excel会被自动转换为数字类型保存。
|
599
721
|
从Excel中读出后为数字类型,因此将会与df的类型不一致
|
600
722
|
"""
|
723
|
+
DEBUG=True
|
601
724
|
|
602
725
|
#检查目录是否存在
|
603
726
|
import os
|
604
727
|
try:
|
605
728
|
os.chdir(filedir)
|
606
729
|
except:
|
607
|
-
print("Error
|
608
|
-
print("Information:",filedir)
|
730
|
+
print(" #Error(save_to_excel): folder does not exist",filedir)
|
609
731
|
return
|
610
732
|
|
611
733
|
#取得df字段列表
|
612
734
|
dflist=df.columns
|
613
735
|
#合成完整的带目录的文件名
|
736
|
+
#filename=filedir+'\\'+excelfile
|
614
737
|
filename=filedir+'/'+excelfile
|
615
738
|
|
616
739
|
import pandas as pd
|
@@ -618,9 +741,9 @@ def save_to_excel(df,filedir,excelfile,sheetname="Sheet1"):
|
|
618
741
|
file1=pd.ExcelFile(excelfile)
|
619
742
|
except:
|
620
743
|
#不存在excelfile文件,直接写入
|
621
|
-
df.to_excel(filename,sheet_name=sheetname,
|
622
|
-
|
623
|
-
print("
|
744
|
+
#df.to_excel(filename,sheet_name=sheetname,header=True,encoding='utf-8')
|
745
|
+
df.to_excel(filename,sheet_name=sheetname,header=True)
|
746
|
+
print(" Successfully saved in",filename,"@ sheet",sheetname)
|
624
747
|
return
|
625
748
|
else:
|
626
749
|
#已存在excelfile文件,先将所有sheet的内容读出到dict中
|
@@ -648,18 +771,25 @@ def save_to_excel(df,filedir,excelfile,sheetname="Sheet1"):
|
|
648
771
|
result=pd.ExcelWriter(filename)
|
649
772
|
for s in sheetlist:
|
650
773
|
df1=dict[s][dflist]
|
651
|
-
df1.to_excel(result,s,header=True,index=True,encoding='utf-8')
|
774
|
+
#df1.to_excel(result,s,header=True,index=True,encoding='utf-8')
|
775
|
+
df1.to_excel(result,s,header=True,index=True)
|
652
776
|
#写入新内容
|
653
777
|
if not dup: #sheetname未重复
|
654
|
-
df.to_excel(result,sheetname,header=True,index=True,encoding='utf-8')
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
778
|
+
#df.to_excel(result,sheetname,header=True,index=True,encoding='utf-8')
|
779
|
+
df.to_excel(result,sheetname,header=True,index=True)
|
780
|
+
if DEBUG:
|
781
|
+
#result.save()
|
782
|
+
result.close()
|
783
|
+
else:
|
784
|
+
try:
|
785
|
+
#result.save()
|
786
|
+
result.close()
|
787
|
+
except:
|
788
|
+
print(" #Error(save_to_excel): writing file failed for",filename)
|
789
|
+
print(" Solution: change file name and try again")
|
790
|
+
return
|
791
|
+
|
792
|
+
print(" Successfully saved in",filename,"@ sheet",sheetname)
|
663
793
|
return
|
664
794
|
#==============================================================================
|
665
795
|
def set_df_period(df,df_min,df_max):
|
@@ -1744,7 +1874,7 @@ if __name__=='__main__':
|
|
1744
1874
|
footnote="This is the footnote"
|
1745
1875
|
|
1746
1876
|
def descriptive_statistics(df,titletxt,footnote,decimals=4,sortby='tpw_mean', \
|
1747
|
-
recommend_only=False,trailing=
|
1877
|
+
recommend_only=False,trailing=7,trend_threshhold=0.01):
|
1748
1878
|
"""
|
1749
1879
|
功能:进行描述性统计,并打印结果
|
1750
1880
|
df的要求:
|
@@ -1764,7 +1894,8 @@ def descriptive_statistics(df,titletxt,footnote,decimals=4,sortby='tpw_mean', \
|
|
1764
1894
|
return
|
1765
1895
|
|
1766
1896
|
# 计算短期趋势
|
1767
|
-
df20=df[-trailing:]
|
1897
|
+
#df20=df[-trailing:]
|
1898
|
+
df20=df.tail(trailing)
|
1768
1899
|
"""
|
1769
1900
|
df20ds=df20.describe()
|
1770
1901
|
df20mean=df20ds[df20ds.index=='mean'].T
|
@@ -1993,6 +2124,259 @@ def descriptive_statistics(df,titletxt,footnote,decimals=4,sortby='tpw_mean', \
|
|
1993
2124
|
|
1994
2125
|
return dst5
|
1995
2126
|
|
2127
|
+
#==============================================================================
|
2128
|
+
|
2129
|
+
if __name__=='__main__':
|
2130
|
+
tickers=['NIO','LI','XPEV','TSLA']
|
2131
|
+
df=compare_mrar(tickers,
|
2132
|
+
rar_name='sharpe',
|
2133
|
+
start='2022-1-1',end='2023-1-31',
|
2134
|
+
market='US',market_index='^GSPC',
|
2135
|
+
window=240,axhline_label='零线')
|
2136
|
+
|
2137
|
+
titletxt="This is the title text"
|
2138
|
+
footnote="This is the footnote"
|
2139
|
+
decimals=4
|
2140
|
+
sortby='tpw_mean'
|
2141
|
+
recommend_only=False
|
2142
|
+
trailing=7
|
2143
|
+
trend_threshhold=0.01
|
2144
|
+
|
2145
|
+
def descriptive_statistics2(df,titletxt,footnote,decimals=4,sortby='tpw_mean', \
|
2146
|
+
recommend_only=False,trailing=7,trend_threshhold=0.01, \
|
2147
|
+
printout=True,style_print=False):
|
2148
|
+
"""
|
2149
|
+
功能:进行描述性统计,并打印结果
|
2150
|
+
df的要求:
|
2151
|
+
索引列为datetime格式,不带时区
|
2152
|
+
各个列为比较对象,均为数值型,降序排列
|
2153
|
+
|
2154
|
+
sortby='tpw_mean':按照近期时间优先加权(time priority weighted)平均数排序
|
2155
|
+
recommend_only=False:是否仅打印推荐的证券
|
2156
|
+
"""
|
2157
|
+
|
2158
|
+
# 检查df
|
2159
|
+
if df is None:
|
2160
|
+
print(" #Error(descriptive_statistics2): none info found")
|
2161
|
+
return
|
2162
|
+
if len(df) == 0:
|
2163
|
+
print(" #Error(descriptive_statistics2): zero data found")
|
2164
|
+
return
|
2165
|
+
|
2166
|
+
# 计算短期趋势
|
2167
|
+
df20=df.tail(trailing)
|
2168
|
+
|
2169
|
+
ds=df.describe(include='all',percentiles=[.5])
|
2170
|
+
dst=ds.T
|
2171
|
+
cols=['min','max','50%','mean','std']
|
2172
|
+
|
2173
|
+
dst['item']=dst.index
|
2174
|
+
cols2=['item','min','max','50%','mean','std']
|
2175
|
+
|
2176
|
+
dst2=dst[cols2]
|
2177
|
+
for c in cols:
|
2178
|
+
dst2[c]=dst2[c].apply(lambda x: round(x,decimals))
|
2179
|
+
|
2180
|
+
if sortby != 'tpw_mean':
|
2181
|
+
if sortby=='median':
|
2182
|
+
sortby='50%'
|
2183
|
+
dst2.sort_values(by=sortby,ascending=False,inplace=True)
|
2184
|
+
|
2185
|
+
cols2cn=['比较对象','最小值','最大值','中位数','平均值','标准差']
|
2186
|
+
dst2.columns=cols2cn
|
2187
|
+
|
2188
|
+
# 近期优先加权平均
|
2189
|
+
dst2['近期优先加权平均']=dst2['比较对象'].apply(lambda x:time_priority_weighted_average(df,x,4))
|
2190
|
+
if sortby == "tpw_mean":
|
2191
|
+
dst2.sort_values(by='近期优先加权平均',ascending=False,inplace=True)
|
2192
|
+
|
2193
|
+
dst3=dst2
|
2194
|
+
dst3=dst3[(dst3['比较对象'] != 'time_weight') & (dst3['比较对象'] != 'relative_weight')]
|
2195
|
+
|
2196
|
+
dst3.reset_index(drop=True,inplace=True)
|
2197
|
+
dst3.index=dst3.index+1
|
2198
|
+
|
2199
|
+
# 趋势标记
|
2200
|
+
dst3['期间趋势']=dst3['比较对象'].apply(lambda x:curve_trend_direct(df,x,trend_threshhold))
|
2201
|
+
dst3['近期趋势']=dst3['比较对象'].apply(lambda x:curve_trend_direct(df20,x,trend_threshhold))
|
2202
|
+
|
2203
|
+
# 推荐标记:最大五颗星
|
2204
|
+
dst3['推荐标记']=''
|
2205
|
+
if sortby in ['tpw_mean','trailing']: #重视近期趋势
|
2206
|
+
#注意:务必先加后减!
|
2207
|
+
#若近期优先加权平均>0,给3星
|
2208
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'+++') if (x['近期优先加权平均']>0) else x['推荐标记'],axis=1)
|
2209
|
+
#若近期趋势➹,加2星
|
2210
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'++') if (x['近期趋势']=='➹') else x['推荐标记'],axis=1)
|
2211
|
+
#若期间趋势➹,加1星
|
2212
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'+') if (x['期间趋势']=='➹') else x['推荐标记'],axis=1)
|
2213
|
+
#若平均值或中位数>0,加1星
|
2214
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'+') if (x['平均值']>0) | (x['中位数']>0) else x['推荐标记'],axis=1)
|
2215
|
+
#若最小值>0,加1星
|
2216
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'+') if (x['最小值']>0) else x['推荐标记'],axis=1)
|
2217
|
+
|
2218
|
+
#若近期趋势➷,减2星
|
2219
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'-') if (x['近期趋势']=='➷') else x['推荐标记'],axis=1)
|
2220
|
+
#若期间趋势➷,减1星
|
2221
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'-') if (x['期间趋势']=='➷') else x['推荐标记'],axis=1)
|
2222
|
+
#若平均值且中位数<0,减1星
|
2223
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'-') if (x['平均值']<0) & (x['中位数']<0) else x['推荐标记'],axis=1)
|
2224
|
+
#若最小值<0,减1星
|
2225
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'-') if (x['最小值']<0) else x['推荐标记'],axis=1)
|
2226
|
+
|
2227
|
+
#若近期优先加权平均<0,星星清零
|
2228
|
+
dst3['推荐标记']=dst3.apply(lambda x: '' if (x['近期优先加权平均']<0) else x['推荐标记'],axis=1)
|
2229
|
+
|
2230
|
+
elif sortby == 'min': #保守推荐
|
2231
|
+
#若最小值>0,加5星
|
2232
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'+++++') if (x['最小值']>0) else x['推荐标记'],axis=1)
|
2233
|
+
#若近期优先加权平均>0,加1星
|
2234
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'+') if (x['近期优先加权平均']>0) else x['推荐标记'],axis=1)
|
2235
|
+
#若近期趋势➹,加1星
|
2236
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'+') if (x['近期趋势']=='➹') else x['推荐标记'],axis=1)
|
2237
|
+
#若期间趋势➹,加1星
|
2238
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'+') if (x['期间趋势']=='➹') else x['推荐标记'],axis=1)
|
2239
|
+
#若平均值或中位数>0,加1星
|
2240
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'+') if (x['平均值']>0) | (x['中位数']>0) else x['推荐标记'],axis=1)
|
2241
|
+
|
2242
|
+
#若近期优先加权平均<0,减1星
|
2243
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'-') if (x['近期优先加权平均']<0) else x['推荐标记'],axis=1)
|
2244
|
+
#若平均值且中位数<0,减1星
|
2245
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'-') if (x['平均值']<0) & (x['中位数']<0) else x['推荐标记'],axis=1)
|
2246
|
+
#若近期趋势➷,减1星
|
2247
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'-') if (x['近期趋势']=='➷') else x['推荐标记'],axis=1)
|
2248
|
+
#若期间趋势➷,减1星
|
2249
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'-') if (x['期间趋势']=='➷') else x['推荐标记'],axis=1)
|
2250
|
+
|
2251
|
+
elif sortby == 'mean': #进取推荐,均值,重视整体趋势,不在乎近期趋势
|
2252
|
+
#若平均值>0,给3星
|
2253
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'+++') if (x['平均值']>0) else x['推荐标记'],axis=1)
|
2254
|
+
#若期间趋势➹,加2星
|
2255
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'++') if (x['期间趋势']=='➹') else x['推荐标记'],axis=1)
|
2256
|
+
#若中位数>0,加1星
|
2257
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'+') if (x['中位数']>0) else x['推荐标记'],axis=1)
|
2258
|
+
#若近期趋势➹,加1星
|
2259
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'+') if (x['近期趋势']=='➹') else x['推荐标记'],axis=1)
|
2260
|
+
#若近期优先加权平均>0,加1星
|
2261
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'+') if (x['近期优先加权平均']>0) else x['推荐标记'],axis=1)
|
2262
|
+
#若最小值>0,加1星
|
2263
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'+') if (x['最小值']>0) else x['推荐标记'],axis=1)
|
2264
|
+
|
2265
|
+
#若期间趋势➷,减2星
|
2266
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'-') if (x['期间趋势']=='➷') else x['推荐标记'],axis=1)
|
2267
|
+
#若近期趋势➷,减1星
|
2268
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'-') if (x['近期趋势']=='➷') else x['推荐标记'],axis=1)
|
2269
|
+
#若近期优先加权平均<0,减1星
|
2270
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'-') if (x['近期优先加权平均']<0) else x['推荐标记'],axis=1)
|
2271
|
+
#若中位数<0,减1星
|
2272
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'-') if (x['中位数']<0) else x['推荐标记'],axis=1)
|
2273
|
+
#若最小值<0,减1星
|
2274
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'-') if (x['最小值']<0) else x['推荐标记'],axis=1)
|
2275
|
+
|
2276
|
+
#若平均值<0,星星清零
|
2277
|
+
dst3['推荐标记']=dst3.apply(lambda x: '' if (x['平均值']<0) else x['推荐标记'],axis=1)
|
2278
|
+
|
2279
|
+
elif sortby == 'median': #进取推荐,中位数,看重整体趋势,不在乎近期短期变化
|
2280
|
+
#若中位数>0,给3星
|
2281
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'+++') if (x['中位数']>0) else x['推荐标记'],axis=1)
|
2282
|
+
#若期间趋势➹,加2星
|
2283
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'++') if (x['期间趋势']=='➹') else x['推荐标记'],axis=1)
|
2284
|
+
#若平均值>0,加1星
|
2285
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'+') if (x['平均值']>0) else x['推荐标记'],axis=1)
|
2286
|
+
|
2287
|
+
#若近期趋势➹,加1星
|
2288
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'+') if (x['近期趋势']=='➹') else x['推荐标记'],axis=1)
|
2289
|
+
#若近期优先加权平均>0,加1星
|
2290
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'+') if (x['近期优先加权平均']>0) else x['推荐标记'],axis=1)
|
2291
|
+
#若最小值>0,加1星
|
2292
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'+') if (x['最小值']>0) else x['推荐标记'],axis=1)
|
2293
|
+
|
2294
|
+
#若期间趋势➷,减2星
|
2295
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'-') if (x['期间趋势']=='➷') else x['推荐标记'],axis=1)
|
2296
|
+
#若近期趋势➷,减1星
|
2297
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'-') if (x['近期趋势']=='➷') else x['推荐标记'],axis=1)
|
2298
|
+
#若近期优先加权平均<0,减1星
|
2299
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'-') if (x['近期优先加权平均']<0) else x['推荐标记'],axis=1)
|
2300
|
+
#若平均值<0,减1星
|
2301
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'-') if (x['平均值']<0) else x['推荐标记'],axis=1)
|
2302
|
+
#若最小值<0,减1星
|
2303
|
+
dst3['推荐标记']=dst3.apply(lambda x: change_stars2(x['推荐标记'],'-') if (x['最小值']<0) else x['推荐标记'],axis=1)
|
2304
|
+
|
2305
|
+
#若中位数<0,星星清零
|
2306
|
+
dst3['推荐标记']=dst3.apply(lambda x: '' if (x['中位数']<0) else x['推荐标记'],axis=1)
|
2307
|
+
else:
|
2308
|
+
pass
|
2309
|
+
|
2310
|
+
#最多5颗星星
|
2311
|
+
dst3['推荐标记']=dst3.apply(lambda x: x['推荐标记'][:5] if (hzlen(x['推荐标记'])>5) else x['推荐标记'],axis=1)
|
2312
|
+
#为了打印对齐,强制向左移动,不管用!
|
2313
|
+
#dst3['推荐标记']=dst3.apply(lambda x: x['推荐标记']+' ' if (hzlen(x['推荐标记'])>4) else x['推荐标记'],axis=1)
|
2314
|
+
|
2315
|
+
dst4=dst3
|
2316
|
+
|
2317
|
+
# 重排序:按照星星个数+数值,降序
|
2318
|
+
dst5=dst4
|
2319
|
+
if sortby == "tpw_mean":
|
2320
|
+
dst5.sort_values(by=['推荐标记','近期优先加权平均'],ascending=[False,False],inplace=True)
|
2321
|
+
#dst5.sort_values(by=['推荐标记','近期优先加权平均'],ascending=False,inplace=True)
|
2322
|
+
elif sortby == "min":
|
2323
|
+
dst5.sort_values(by=['推荐标记','最小值'],ascending=[False,False],inplace=True)
|
2324
|
+
elif sortby == "mean":
|
2325
|
+
dst5.sort_values(by=['推荐标记','平均值'],ascending=[False,False],inplace=True)
|
2326
|
+
elif sortby == "median":
|
2327
|
+
dst5.sort_values(by=['推荐标记','中位数'],ascending=[False,False],inplace=True)
|
2328
|
+
elif sortby == "trailing":
|
2329
|
+
dst5.sort_values(by=['推荐标记','最新均值差'],ascending=[False,False],inplace=True)
|
2330
|
+
else:
|
2331
|
+
pass
|
2332
|
+
|
2333
|
+
#是否过滤无推荐标志的证券,防止过多无推荐标志的记录使得打印列表过长
|
2334
|
+
if recommend_only:
|
2335
|
+
dst6=dst5[dst5['推荐标记'] != '']
|
2336
|
+
dst_num=len(dst6)
|
2337
|
+
#若无推荐标志也要显示头十个
|
2338
|
+
if dst_num < 10:
|
2339
|
+
dst6=dst5.head(10)
|
2340
|
+
else:
|
2341
|
+
dst6=dst5.head(dst_num+3)
|
2342
|
+
else:
|
2343
|
+
dst6=dst5
|
2344
|
+
|
2345
|
+
dst6.reset_index(drop=True,inplace=True)
|
2346
|
+
dst6.index=dst6.index+1
|
2347
|
+
|
2348
|
+
if printout:
|
2349
|
+
#控制显示的小数点位数
|
2350
|
+
for c in dst6.columns:
|
2351
|
+
try:
|
2352
|
+
dst6[c]=dst6[c].apply(lambda x: round(x,4))
|
2353
|
+
except:
|
2354
|
+
pass
|
2355
|
+
#确保display显示时不再自动在数值尾部添加零至6位小数
|
2356
|
+
dst6[c]=dst6[c].apply(lambda x: str(x))
|
2357
|
+
|
2358
|
+
if not style_print: #markdown打印
|
2359
|
+
print("\n"+titletxt+"\n")
|
2360
|
+
#如果index=True则显示index,这样alignlist的长度就需要dst6列数+1
|
2361
|
+
alignlist=['right','left']+['center']*(len(list(dst6))-3)+['center','left']
|
2362
|
+
try:
|
2363
|
+
print(dst6.to_markdown(index=True,tablefmt='plain',colalign=alignlist))
|
2364
|
+
except:
|
2365
|
+
#解决汉字编码gbk出错问题
|
2366
|
+
dst7=dst6.to_markdown(index=True,tablefmt='plain',colalign=alignlist)
|
2367
|
+
dst8=dst7.encode("utf-8",errors="strict")
|
2368
|
+
print(dst8)
|
2369
|
+
print("\n"+footnote)
|
2370
|
+
|
2371
|
+
else: #style打印
|
2372
|
+
print("\n"+titletxt)
|
2373
|
+
dst6sd= dst6.style.set_properties(**{'text-align': 'center'})
|
2374
|
+
from IPython.display import display
|
2375
|
+
display(dst6sd)
|
2376
|
+
print(footnote+"\n")
|
2377
|
+
|
2378
|
+
return dst5
|
2379
|
+
|
1996
2380
|
|
1997
2381
|
#==============================================================================
|
1998
2382
|
if __name__=='__main__':
|
@@ -2010,6 +2394,31 @@ def print_list(alist,leading_blanks=1):
|
|
2010
2394
|
print('\n')
|
2011
2395
|
|
2012
2396
|
return
|
2397
|
+
|
2398
|
+
if __name__=='__main__':
|
2399
|
+
alist=['NIO','LI','XPEV','TSLA']
|
2400
|
+
list2str(alist)
|
2401
|
+
|
2402
|
+
def list2str(alist):
|
2403
|
+
"""
|
2404
|
+
功能:将列表转换为字符串,不带引号,节省空间
|
2405
|
+
"""
|
2406
|
+
if len(alist) > 1:
|
2407
|
+
result='['
|
2408
|
+
for i in alist:
|
2409
|
+
result=result+str(i)
|
2410
|
+
if i != alist[-1]:
|
2411
|
+
result=result+', '
|
2412
|
+
result=result+']'
|
2413
|
+
|
2414
|
+
elif len(alist) == 1:
|
2415
|
+
result=str(alist[0])
|
2416
|
+
|
2417
|
+
else:
|
2418
|
+
result=''
|
2419
|
+
|
2420
|
+
return result
|
2421
|
+
|
2013
2422
|
#==============================================================================
|
2014
2423
|
# FUNCTION TO REMOVE TIMEZONE
|
2015
2424
|
def remove_timezone(dt):
|
@@ -2144,18 +2553,18 @@ def curve_trend_regress(df,col,threshhold=0.0001):
|
|
2144
2553
|
|
2145
2554
|
return result
|
2146
2555
|
|
2147
|
-
def curve_trend_direct(df,col,threshhold=0.
|
2556
|
+
def curve_trend_direct(df,col,threshhold=0.01):
|
2148
2557
|
"""
|
2149
2558
|
功能:直接对比首尾值大小。目的为判断曲线走势
|
2150
2559
|
|
2151
2560
|
输入项:
|
2152
2561
|
df: 数据框,假设其索引为日期项,且已升序排列
|
2153
2562
|
col: 考察变量,检查该变量的走势,向上,向下,or 不明显(无显著性星星)
|
2154
|
-
|
2155
|
-
|
2156
|
-
'➠'
|
2157
|
-
'➷'
|
2158
|
-
'➹'
|
2563
|
+
threshhold:相对值
|
2564
|
+
返回值:(尾值-首值)/首值
|
2565
|
+
'➠':变化率接近零(其绝对值小于threshhold)
|
2566
|
+
'➷':变化率为负数且其绝对值不小于threshhold
|
2567
|
+
'➹':变化率为正数且其绝对值不小于threshhold
|
2159
2568
|
"""
|
2160
2569
|
# 检查df是否为空
|
2161
2570
|
if df is None:
|
@@ -2168,15 +2577,32 @@ def curve_trend_direct(df,col,threshhold=0.0001):
|
|
2168
2577
|
df1.sort_index(ascending=True,inplace=True)
|
2169
2578
|
first_value=df1.head(1)[col].values[0]
|
2170
2579
|
last_value=df1.tail(1)[col].values[0]
|
2171
|
-
|
2580
|
+
|
2581
|
+
#采用相对值,避免数量级差异,同时避免负负得正
|
2582
|
+
if first_value != 0.0:
|
2583
|
+
diff=(last_value - first_value)/abs(first_value)
|
2584
|
+
elif last_value != 0.0:
|
2585
|
+
#不得已
|
2586
|
+
diff=(last_value - first_value)/abs(last_value)
|
2587
|
+
else:
|
2588
|
+
#实在不得已
|
2589
|
+
diff=last_value - first_value
|
2590
|
+
|
2172
2591
|
diff_abs=abs(diff)
|
2173
2592
|
|
2174
2593
|
# 判断斜率方向
|
2175
2594
|
result='➠'
|
2595
|
+
"""
|
2176
2596
|
if diff_abs >= threshhold and diff > 0:
|
2177
2597
|
result='➹'
|
2178
2598
|
if diff_abs >= threshhold and diff < 0:
|
2179
2599
|
result='➷'
|
2600
|
+
"""
|
2601
|
+
#留出区间-threshhold至threshhold视为平行趋势
|
2602
|
+
if diff > threshhold:
|
2603
|
+
result='➹'
|
2604
|
+
if diff < -threshhold:
|
2605
|
+
result='➷'
|
2180
2606
|
|
2181
2607
|
return result
|
2182
2608
|
#==============================================================================
|
@@ -2244,8 +2670,40 @@ def change_recommend_stars(stars_current,change='+'):
|
|
2244
2670
|
stars_new=stars2
|
2245
2671
|
|
2246
2672
|
return stars_new
|
2673
|
+
|
2674
|
+
#==============================================================================
|
2675
|
+
if __name__=='__main__':
|
2676
|
+
stars_current=''
|
2677
|
+
stars_current='✮✮'
|
2678
|
+
|
2679
|
+
change='+'
|
2680
|
+
change='++'
|
2681
|
+
change='-'
|
2682
|
+
|
2683
|
+
change_stars2(stars_current,change)
|
2684
|
+
|
2685
|
+
def change_stars2(stars_current,change='+'):
|
2686
|
+
"""
|
2687
|
+
功能:增减推荐的星星个数
|
2688
|
+
注意:change中不能同时出现+-符号,只能出现一种,但可以多个
|
2689
|
+
"""
|
2690
|
+
stars1='✮'
|
2247
2691
|
|
2692
|
+
num_plus=change.count('+')
|
2693
|
+
if num_plus > 0:
|
2694
|
+
stars_new=stars_current+stars1 * num_plus
|
2248
2695
|
|
2696
|
+
num_minus=change.count('-')
|
2697
|
+
if num_minus >= 1:
|
2698
|
+
stars_new=stars_current
|
2699
|
+
for n in range(1,num_minus+1):
|
2700
|
+
stars_new=stars_new[:-1]
|
2701
|
+
if hzlen(stars_new)==0: break
|
2702
|
+
"""
|
2703
|
+
if hzlen(stars_new)>5:
|
2704
|
+
stars_new=stars_new[:5]
|
2705
|
+
"""
|
2706
|
+
return stars_new
|
2249
2707
|
|
2250
2708
|
#==============================================================================
|
2251
2709
|
if __name__=='__main__':
|
@@ -2320,6 +2778,12 @@ def fix_package(file='stooq.py',package='pandas_datareader'):
|
|
2320
2778
|
"""
|
2321
2779
|
功能:修复stooq.py,使用siat包中的stooq.py覆盖pandas_datareader中的同名文件
|
2322
2780
|
注意:执行本程序需要系统管理员权限,可以系统管理员权限启动Jupyter或Spyder
|
2781
|
+
|
2782
|
+
改进:建立一个Excel文件,记录需要修复的文件和包,例如:
|
2783
|
+
file package
|
2784
|
+
stooq.py pandas_datareader
|
2785
|
+
bond_zh_sina.py akshare
|
2786
|
+
|
2323
2787
|
"""
|
2324
2788
|
#判断操作系统
|
2325
2789
|
import sys; czxt=sys.platform
|
@@ -2420,7 +2884,7 @@ def df_preprocess(dfs,measure,axhline_label,x_label,y_label,lang='Chinese', \
|
|
2420
2884
|
#相对起点值变化的百分数(起点值为0)
|
2421
2885
|
scalinglist=['mean','min','start','percentage','change%']
|
2422
2886
|
if not (scaling_option in scalinglist):
|
2423
|
-
print(" #Error(
|
2887
|
+
print(" #Error(df_preprocess): invalid scaling option",scaling_option)
|
2424
2888
|
print(" Valid scaling option:",scalinglist)
|
2425
2889
|
return None
|
2426
2890
|
if scaling_option == 'mean':
|
@@ -2536,7 +3000,8 @@ def df_preprocess(dfs,measure,axhline_label,x_label,y_label,lang='Chinese', \
|
|
2536
3000
|
measure_suffix='(相对百分数%)'
|
2537
3001
|
elif scaling_option == 'change%':
|
2538
3002
|
std_notes="注释:为突出变化趋势,图中数值为相对期间起点的增减百分比"
|
2539
|
-
measure_suffix='(增/减%)'
|
3003
|
+
#measure_suffix='(增/减%)'
|
3004
|
+
measure_suffix='(涨跌幅度%)'
|
2540
3005
|
axhline_label='零线' #可以在security_trend中使用critical_value选项指定水平线位置,默认0
|
2541
3006
|
#axhline_value=0
|
2542
3007
|
|
@@ -2550,4 +3015,266 @@ def df_preprocess(dfs,measure,axhline_label,x_label,y_label,lang='Chinese', \
|
|
2550
3015
|
#返回内容
|
2551
3016
|
return dfs2,axhline_label,x_label,y_label,plus_sign
|
2552
3017
|
#==============================================================================
|
3018
|
+
if __name__=='__main__':
|
3019
|
+
is_running_in_jupyter()
|
3020
|
+
|
3021
|
+
|
3022
|
+
def is_running_in_jupyter():
|
3023
|
+
"""
|
3024
|
+
功能:检测当前环境是否在Jupyter中,误判Spyder为Jupyter,不行!
|
3025
|
+
"""
|
3026
|
+
try:
|
3027
|
+
# 尝试导入IPython的一些模块
|
3028
|
+
from IPython import get_ipython
|
3029
|
+
|
3030
|
+
ipython = get_ipython()
|
3031
|
+
if 'IPKernelApp' not in ipython.config:
|
3032
|
+
return False
|
3033
|
+
return True
|
3034
|
+
|
3035
|
+
except ImportError:
|
3036
|
+
return False
|
3037
|
+
|
3038
|
+
#==============================================================================
|
3039
|
+
if __name__=='__main__':
|
3040
|
+
date1=pd.to_datetime('2024-1-2')
|
3041
|
+
date2=pd.to_datetime('2024-1-9')
|
3042
|
+
days_between_dates(date1, date2)
|
3043
|
+
|
3044
|
+
def days_between_dates(date1, date2):
|
3045
|
+
"""
|
3046
|
+
注意:date1和date2为datetime类型
|
3047
|
+
"""
|
3048
|
+
from datetime import datetime
|
3049
|
+
delta = date2 - date1
|
3050
|
+
return delta.days
|
3051
|
+
|
3052
|
+
#==============================================================================
|
3053
|
+
if __name__=='__main__':
|
3054
|
+
stars_num=0
|
3055
|
+
stars_num=3
|
3056
|
+
stars_num=4.2
|
3057
|
+
stars_num=4.6
|
3058
|
+
|
3059
|
+
generate_stars(stars_num)
|
3060
|
+
|
3061
|
+
def generate_stars(stars_num):
|
3062
|
+
"""
|
3063
|
+
功能:基于星星个数stars_num生成推荐星星符号,支持半颗星
|
3064
|
+
"""
|
3065
|
+
stars1='✮'
|
3066
|
+
starsh='☆'
|
3067
|
+
|
3068
|
+
stars_int=int(stars_num)
|
3069
|
+
result=stars_int * stars1
|
3070
|
+
|
3071
|
+
if (stars_num - stars_int) >= 0.5:
|
3072
|
+
result=result + starsh
|
3073
|
+
|
3074
|
+
return result
|
3075
|
+
|
3076
|
+
|
3077
|
+
#==============================================================================
|
3078
|
+
if __name__=='__main__':
|
3079
|
+
df=get_price('000001.SS','2000-1-1','2024-3-22')
|
3080
|
+
column='Close'
|
3081
|
+
minimum=30
|
3082
|
+
method='max'
|
3083
|
+
|
3084
|
+
df1=df[column].resample('4H').max()
|
3085
|
+
df2=df1.interpolate(method='cubic')
|
3086
|
+
|
3087
|
+
period='24H'
|
3088
|
+
df2=df_resampling(df,column,period,method='mean',minimum=minimum)
|
3089
|
+
df2[column].plot(title=period)
|
3090
|
+
|
3091
|
+
|
3092
|
+
period='auto'; method='mean'; minimum=50
|
3093
|
+
df2=df_resampling(df,column,period,method='mean',minimum=minimum)
|
3094
|
+
df2[column].plot()
|
3095
|
+
|
3096
|
+
|
3097
|
+
def df_resampling(df,column,period='auto',method='max',minimum=30):
|
3098
|
+
"""
|
3099
|
+
注意:未完成状态。遇到的问题:平滑后数据的后面时间段丢失严重!
|
3100
|
+
目的:将大量时间序列数据绘制重新采样,减少极端值,使得数据趋势简洁明了,可能丢失部分细节
|
3101
|
+
功能:将df按照period对column字段数值重新采样,采样方法为method,采样前个数不少于minimum
|
3102
|
+
注意:df需为时间序列;column为单个字段,需为数值型
|
3103
|
+
period:采样间隔,支持小时'H'或'nH'(n=2,3,...)、周'W'、月'M'、季'Q'或年'Y',默认由系统决定
|
3104
|
+
method:暂仅支持平均值方法mean(典型)和求和方法sum
|
3105
|
+
minimum:采样后需保留的最少数据个数,默认30个
|
3106
|
+
"""
|
3107
|
+
DEBUG=True
|
3108
|
+
|
3109
|
+
import pandas as pd
|
3110
|
+
import numpy as np
|
3111
|
+
|
3112
|
+
#检查df长度:是否需要重新采样
|
3113
|
+
if len(df) <= minimum:
|
3114
|
+
if DEBUG: print(" #Notice(df_resampling): no need to resample",len(df))
|
3115
|
+
return df #无需重新采样,返回原值
|
3116
|
+
|
3117
|
+
#仅对采样字段进行处理
|
3118
|
+
if column not in df.columns:
|
3119
|
+
if DEBUG: print(" #Warning(df_resampling): non-exist column",column)
|
3120
|
+
return df #返回原值
|
3121
|
+
|
3122
|
+
#取出采样字段
|
3123
|
+
df1=df[[column]].copy() #避免影响到原值
|
3124
|
+
|
3125
|
+
#寻求最佳采样间隔
|
3126
|
+
period_list=['2H','4H','6H','8H','12H','24H']
|
3127
|
+
std_list=[]
|
3128
|
+
dft_list=[]
|
3129
|
+
for p in period_list:
|
3130
|
+
dft1=df1[column].resample(p).mean()
|
3131
|
+
dft2=dft1.interpolate(method='linear')
|
3132
|
+
stdt=dft2.std()
|
3133
|
+
std_list=std_list+[stdt]
|
3134
|
+
dft_list=dft_list+[dft2]
|
3135
|
+
|
3136
|
+
std_min=min(std_list)
|
3137
|
+
pos=std_list.index(std_min)
|
3138
|
+
period_min=period_list[pos]
|
3139
|
+
df2=dft_list[pos]
|
3140
|
+
|
3141
|
+
|
3142
|
+
#再次检查采样后的长度
|
3143
|
+
if len(df2) < minimum:
|
3144
|
+
if DEBUG: print(" #Warning(df_resampling): resampled number",len(df2),"< minimum",minimum)
|
3145
|
+
return df #返回原值
|
3146
|
+
|
3147
|
+
return df2
|
3148
|
+
|
3149
|
+
#==============================================================================
|
3150
|
+
if __name__=='__main__':
|
3151
|
+
df=get_price('000001.SS','2000-1-1','2024-3-22')
|
3152
|
+
|
3153
|
+
|
3154
|
+
def linewidth_adjust(df):
|
3155
|
+
"""
|
3156
|
+
功能:根据df中元素个数多少调节绘制曲线时线段的宽度linewidth
|
3157
|
+
"""
|
3158
|
+
|
3159
|
+
dflen=len(df)
|
3160
|
+
if dflen > 100: lwadjust=1.2
|
3161
|
+
elif dflen > 200: lwadjust=1.0
|
3162
|
+
elif dflen > 300: lwadjust=0.8
|
3163
|
+
elif dflen > 500: lwadjust=0.4
|
3164
|
+
elif dflen > 1000: lwadjust=0.2
|
3165
|
+
elif dflen > 2000: lwadjust=0.1
|
3166
|
+
elif dflen > 3000: lwadjust=0.05
|
3167
|
+
elif dflen > 5000: lwadjust=0.01
|
3168
|
+
else: lwadjust=1.5
|
3169
|
+
|
3170
|
+
return lwadjust
|
3171
|
+
|
3172
|
+
#==============================================================================
|
3173
|
+
if __name__=='__main__':
|
3174
|
+
start='MRM'
|
3175
|
+
start='L3M'
|
3176
|
+
start='MRY'
|
3177
|
+
start='L30Y'
|
3178
|
+
|
3179
|
+
start='default'; end='default'
|
3180
|
+
|
3181
|
+
start='2024-1-1'; end='2023-1-1'
|
3182
|
+
|
3183
|
+
start_end_preprocess(start,end='today')
|
3184
|
+
|
3185
|
+
def start_end_preprocess(start,end='today'):
|
3186
|
+
"""
|
3187
|
+
功能:处理简约日期为具体日期,并检查日期的合理性
|
3188
|
+
"""
|
3189
|
+
|
3190
|
+
# 检查日期:截至日期
|
3191
|
+
import datetime as dt;
|
3192
|
+
todaydt=dt.date.today();todaystr=todaydt.strftime('%Y-%m-%d')
|
3193
|
+
|
3194
|
+
end=end.lower()
|
3195
|
+
if end in ['default','today']:
|
3196
|
+
todate=todaystr
|
3197
|
+
else:
|
3198
|
+
validdate,todate=check_date2(end)
|
3199
|
+
if not validdate:
|
3200
|
+
print(" #Warning(start_end_preprocess): invalid date for",end)
|
3201
|
+
todate=todaystr
|
3202
|
+
|
3203
|
+
# 检查日期:开始日期
|
3204
|
+
start=start.lower()
|
3205
|
+
|
3206
|
+
"""
|
3207
|
+
if start in ['default','mrm','l1m']: # 默认近一个月
|
3208
|
+
fromdate=date_adjust(todate,adjust=-31-7) #多几天有利于绘图坐标标示
|
3209
|
+
elif start in ['l2m']: # 近2个月
|
3210
|
+
fromdate=date_adjust(todate,adjust=-31*2-14)
|
3211
|
+
elif start in ['mrq','l3m']: # 近三个月
|
3212
|
+
fromdate=date_adjust(todate,adjust=-31*3-16)
|
3213
|
+
elif start in ['l6m','mrh']: # 近6个月
|
3214
|
+
fromdate=date_adjust(todate,adjust=-31*6-16)
|
3215
|
+
elif start in ['mry','l12m']: # 近一年
|
3216
|
+
fromdate=date_adjust(todate,adjust=-366-16)
|
3217
|
+
elif start in ['l2y']: # 近两年以来
|
3218
|
+
fromdate=date_adjust(todate,adjust=-366*2-15)
|
3219
|
+
elif start in ['l3y']: # 近三年以来
|
3220
|
+
fromdate=date_adjust(todate,adjust=-366*3-14)
|
3221
|
+
elif start in ['l5y']: # 近五年以来
|
3222
|
+
fromdate=date_adjust(todate,adjust=-366*5-13)
|
3223
|
+
elif start in ['l8y']: # 近八年以来
|
3224
|
+
fromdate=date_adjust(todate,adjust=-366*8-11)
|
3225
|
+
elif start in ['l10y']: # 近十年以来
|
3226
|
+
fromdate=date_adjust(todate,adjust=-366*10-9)
|
3227
|
+
elif start in ['l20y']: # 近20年以来
|
3228
|
+
fromdate=date_adjust(todate,adjust=-366*20-1)
|
3229
|
+
elif start in ['l30y']: # 近30年以来
|
3230
|
+
fromdate=date_adjust(todate,adjust=-366*30)
|
3231
|
+
elif start in ['ytd']: # 今年以来
|
3232
|
+
fromdate=str(todaydt.year-1)+'-12-1'
|
3233
|
+
else:
|
3234
|
+
validdate,fromdate=check_date2(start)
|
3235
|
+
if not validdate:
|
3236
|
+
print(" #Warning(security_trend): invalid date for",start,"/b, reset to MRM")
|
3237
|
+
fromdate=date_adjust(todate,adjust=-31-16)
|
3238
|
+
"""
|
3239
|
+
if start in ['default','mrm','l1m']: # 默认近一个月
|
3240
|
+
fromdate=date_adjust2(todate,adjust_month=-1,adjust_day=-1) #有利于绘图横坐标日期标示
|
3241
|
+
elif start in ['l2m']: # 近2个月
|
3242
|
+
fromdate=date_adjust2(todate,adjust_month=-2,adjust_day=-1)
|
3243
|
+
elif start in ['mrq','l3m']: # 近三个月
|
3244
|
+
fromdate=date_adjust2(todate,adjust_month=-3,adjust_day=-1)
|
3245
|
+
elif start in ['l6m','mrh']: # 近6个月
|
3246
|
+
fromdate=date_adjust2(todate,adjust_month=-6,adjust_day=-1)
|
3247
|
+
elif start in ['mry','l12m']: # 近一年
|
3248
|
+
fromdate=date_adjust2(todate,adjust_year=-1,to_prev_month_end=True)
|
3249
|
+
elif start in ['l2y']: # 近两年以来
|
3250
|
+
fromdate=date_adjust2(todate,adjust_year=-2,to_prev_month_end=True)
|
3251
|
+
elif start in ['l3y']: # 近三年以来
|
3252
|
+
fromdate=date_adjust2(todate,adjust_year=-3,to_prev_month_end=True)
|
3253
|
+
elif start in ['l5y']: # 近五年以来
|
3254
|
+
fromdate=date_adjust2(todate,adjust_year=-5,to_prev_year_end=True)
|
3255
|
+
elif start in ['l8y']: # 近八年以来
|
3256
|
+
fromdate=date_adjust2(todate,adjust_year=-8,to_prev_year_end=True)
|
3257
|
+
elif start in ['l10y']: # 近十年以来
|
3258
|
+
fromdate=date_adjust2(todate,adjust_year=-10,to_prev_year_end=True)
|
3259
|
+
elif start in ['l20y']: # 近20年以来
|
3260
|
+
fromdate=date_adjust2(todate,adjust_year=-20,to_prev_year_end=True)
|
3261
|
+
elif start in ['l30y']: # 近30年以来
|
3262
|
+
fromdate=date_adjust2(todate,adjust_year=-30,to_prev_year_end=True)
|
3263
|
+
elif start in ['ytd']: # 今年以来
|
3264
|
+
fromdate=str(todaydt.year-1)+'-12-31'
|
3265
|
+
else:
|
3266
|
+
validdate,fromdate=check_date2(start)
|
3267
|
+
if not validdate:
|
3268
|
+
print(" #Warning(security_trend): invalid date",start)
|
3269
|
+
fromdate=date_adjust2(todate,adjust_month=-1,adjust_day=-1)
|
3270
|
+
|
3271
|
+
result,_,_=check_period(fromdate,todate)
|
3272
|
+
if not result:
|
3273
|
+
todate=todaystr
|
3274
|
+
print(" #Warning(start_end_preprocess): invalid date period between",fromdate,todate)
|
3275
|
+
|
3276
|
+
return fromdate,todate
|
3277
|
+
|
3278
|
+
#==============================================================================
|
3279
|
+
#==============================================================================
|
2553
3280
|
|