siat 2.14.1__py3-none-any.whl → 3.0.0__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 +1 -0
- siat/assets_liquidity.py +16 -16
- siat/beta_adjustment.py +6 -6
- siat/beta_adjustment_china.py +9 -9
- siat/bond.py +71 -67
- siat/capm_beta.py +11 -11
- siat/capm_beta2.py +49 -23
- siat/common.py +451 -76
- siat/compare_cross.py +15 -82
- siat/exchange_bond_china.pickle +0 -0
- siat/fama_french.py +3 -3
- siat/financials.py +15 -15
- siat/financials2.py +8 -8
- siat/financials_china.py +20 -20
- siat/financials_china2.py +25 -25
- siat/fund_china.pickle +0 -0
- siat/fund_china.py +5 -4
- siat/grafix.py +197 -132
- siat/markowitz.py +6 -5
- siat/option_china.py +1 -1
- siat/option_pricing.py +6 -6
- siat/risk_adjusted_return.py +14 -14
- siat/risk_adjusted_return2.py +64 -42
- siat/risk_evaluation.py +32 -32
- siat/risk_free_rate.py +0 -0
- siat/sector_china.py +3 -195
- siat/security_price2.py +616 -0
- siat/security_prices.py +935 -308
- siat/security_trend2.py +28 -47
- siat/stock.py +225 -437
- siat/stock_china.py +19 -19
- siat/stock_info.pickle +0 -0
- siat/stock_technical.py +547 -144
- siat/transaction.py +3 -3
- siat/translate.py +781 -24
- siat/valuation.py +6 -6
- siat/var_model_validation.py +2 -2
- {siat-2.14.1.dist-info → siat-3.0.0.dist-info}/METADATA +1 -1
- {siat-2.14.1.dist-info → siat-3.0.0.dist-info}/RECORD +41 -40
- {siat-2.14.1.dist-info → siat-3.0.0.dist-info}/WHEEL +0 -0
- {siat-2.14.1.dist-info → siat-3.0.0.dist-info}/top_level.txt +0 -0
siat/common.py
CHANGED
@@ -16,11 +16,11 @@ SIAT:Security Investment Analysis Tool
|
|
16
16
|
#==============================================================================
|
17
17
|
#关闭所有警告
|
18
18
|
import warnings; warnings.filterwarnings('ignore')
|
19
|
-
|
20
|
-
#==============================================================================
|
21
|
-
SUFFIX_LIST_CN=['SS','SZ','BJ','NQ']
|
22
19
|
import pandas as pd
|
23
20
|
#==============================================================================
|
21
|
+
SUFFIX_LIST_CN=['SS','SZ','BJ','SW','SH']
|
22
|
+
SUFFIX_LIST_HK=['HK']
|
23
|
+
#==============================================================================
|
24
24
|
#设置全局语言环境
|
25
25
|
import pickle
|
26
26
|
|
@@ -239,19 +239,26 @@ def check_period(fromdate, todate):
|
|
239
239
|
try:
|
240
240
|
start=pd.to_datetime(fromdate)
|
241
241
|
except:
|
242
|
-
print("
|
242
|
+
print(" #Error(check_period), invalid date:",fromdate)
|
243
|
+
return None, None, None
|
244
|
+
|
245
|
+
#开始日期不能晚于今日
|
246
|
+
import datetime
|
247
|
+
todaydt = pd.to_datetime(datetime.date.today())
|
248
|
+
if start > todaydt:
|
249
|
+
print(" #Error(check_period), invalid start date:",fromdate)
|
243
250
|
return None, None, None
|
244
251
|
|
245
252
|
#测试结束日期的合理性
|
246
253
|
try:
|
247
254
|
end=pd.to_datetime(todate)
|
248
255
|
except:
|
249
|
-
print("
|
256
|
+
print(" #Error(check_period): invalid date:",todate)
|
250
257
|
return None, None, None
|
251
258
|
|
252
259
|
#测试日期期间的合理性
|
253
260
|
if start > end:
|
254
|
-
print("
|
261
|
+
print(" #Error(check_period): invalid period: from",fromdate,"to",todate)
|
255
262
|
return None, None, None
|
256
263
|
|
257
264
|
return True, start, end
|
@@ -417,6 +424,8 @@ def date_adjust2(basedate,adjust_year=0,adjust_month=0,adjust_day=0, \
|
|
417
424
|
#==============================================================================
|
418
425
|
if __name__ =="__main__":
|
419
426
|
portfolio={'Market':('US','^GSPC'),'EDU':0.4,'TAL':0.3,'TEDU':0.2}
|
427
|
+
|
428
|
+
portfolio={'Market':('China','000001.SS','股债基组合'),'600519.SS':50,'sh010504':150,'sh010504':300}
|
420
429
|
|
421
430
|
def decompose_portfolio(portfolio):
|
422
431
|
"""
|
@@ -426,7 +435,7 @@ def decompose_portfolio(portfolio):
|
|
426
435
|
输出:市场,市场指数,股票代码列表和份额列表
|
427
436
|
"""
|
428
437
|
#从字典中提取信息
|
429
|
-
keylist=list(portfolio.keys())
|
438
|
+
keylist=list(portfolio.keys()) #注意:字典中相同的键会被合并为一个
|
430
439
|
scope=portfolio[keylist[0]][0]
|
431
440
|
mktidx=portfolio[keylist[0]][1]
|
432
441
|
|
@@ -720,19 +729,20 @@ def save_to_excel(df,filedir,excelfile,sheetname="Sheet1"):
|
|
720
729
|
注意:如果df中含有以文本表示的数字,写入到Excel会被自动转换为数字类型保存。
|
721
730
|
从Excel中读出后为数字类型,因此将会与df的类型不一致
|
722
731
|
"""
|
732
|
+
DEBUG=True
|
723
733
|
|
724
734
|
#检查目录是否存在
|
725
735
|
import os
|
726
736
|
try:
|
727
737
|
os.chdir(filedir)
|
728
738
|
except:
|
729
|
-
print("Error
|
730
|
-
print("Information:",filedir)
|
739
|
+
print(" #Error(save_to_excel): folder does not exist",filedir)
|
731
740
|
return
|
732
741
|
|
733
742
|
#取得df字段列表
|
734
743
|
dflist=df.columns
|
735
744
|
#合成完整的带目录的文件名
|
745
|
+
#filename=filedir+'\\'+excelfile
|
736
746
|
filename=filedir+'/'+excelfile
|
737
747
|
|
738
748
|
import pandas as pd
|
@@ -740,9 +750,9 @@ def save_to_excel(df,filedir,excelfile,sheetname="Sheet1"):
|
|
740
750
|
file1=pd.ExcelFile(excelfile)
|
741
751
|
except:
|
742
752
|
#不存在excelfile文件,直接写入
|
743
|
-
df.to_excel(filename,sheet_name=sheetname,
|
744
|
-
|
745
|
-
print("
|
753
|
+
#df.to_excel(filename,sheet_name=sheetname,header=True,encoding='utf-8')
|
754
|
+
df.to_excel(filename,sheet_name=sheetname,header=True)
|
755
|
+
print(" Successfully saved in",filename,"@ sheet",sheetname)
|
746
756
|
return
|
747
757
|
else:
|
748
758
|
#已存在excelfile文件,先将所有sheet的内容读出到dict中
|
@@ -770,18 +780,25 @@ def save_to_excel(df,filedir,excelfile,sheetname="Sheet1"):
|
|
770
780
|
result=pd.ExcelWriter(filename)
|
771
781
|
for s in sheetlist:
|
772
782
|
df1=dict[s][dflist]
|
773
|
-
df1.to_excel(result,s,header=True,index=True,encoding='utf-8')
|
783
|
+
#df1.to_excel(result,s,header=True,index=True,encoding='utf-8')
|
784
|
+
df1.to_excel(result,s,header=True,index=True)
|
774
785
|
#写入新内容
|
775
786
|
if not dup: #sheetname未重复
|
776
|
-
df.to_excel(result,sheetname,header=True,index=True,encoding='utf-8')
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
787
|
+
#df.to_excel(result,sheetname,header=True,index=True,encoding='utf-8')
|
788
|
+
df.to_excel(result,sheetname,header=True,index=True)
|
789
|
+
if DEBUG:
|
790
|
+
#result.save()
|
791
|
+
result.close()
|
792
|
+
else:
|
793
|
+
try:
|
794
|
+
#result.save()
|
795
|
+
result.close()
|
796
|
+
except:
|
797
|
+
print(" #Error(save_to_excel): writing file failed for",filename)
|
798
|
+
print(" Solution: change file name and try again")
|
799
|
+
return
|
800
|
+
|
801
|
+
print(" Successfully saved in",filename,"@ sheet",sheetname)
|
785
802
|
return
|
786
803
|
#==============================================================================
|
787
804
|
def set_df_period(df,df_min,df_max):
|
@@ -1460,7 +1477,7 @@ if __name__=='__main__':
|
|
1460
1477
|
_,_,tickerlist,sharelist=decompose_portfolio(portfolio)
|
1461
1478
|
leading_blanks=2
|
1462
1479
|
|
1463
|
-
def print_tickerlist_sharelist(tickerlist,sharelist,leading_blanks=2):
|
1480
|
+
def print_tickerlist_sharelist(tickerlist,sharelist,leading_blanks=2,ticker_type='auto'):
|
1464
1481
|
"""
|
1465
1482
|
功能:纵向打印投资组合的成分股和持股比例
|
1466
1483
|
输入:
|
@@ -1486,12 +1503,16 @@ def print_tickerlist_sharelist(tickerlist,sharelist,leading_blanks=2):
|
|
1486
1503
|
sharelist_array = np.array(sharelist)
|
1487
1504
|
total_shares=sharelist_array.sum()
|
1488
1505
|
weights=sharelist_array/total_shares
|
1506
|
+
|
1507
|
+
#预处理ticker_type
|
1508
|
+
ticker_type_list=ticker_type_preprocess_mticker_mixed(tickerlist,ticker_type)
|
1489
1509
|
|
1490
1510
|
import pandas as pd
|
1491
1511
|
df=pd.DataFrame(columns=['证券代码','证券名称','持仓比例'])
|
1492
1512
|
for t in tickerlist:
|
1493
1513
|
pos=tickerlist.index(t)
|
1494
|
-
|
1514
|
+
tt=ticker_type_list[pos]
|
1515
|
+
tname=ticker_name(t,tt)
|
1495
1516
|
tweight=weights[pos]
|
1496
1517
|
|
1497
1518
|
row=pd.Series({'证券代码':t,'证券名称':tname,'持仓比例':tweight})
|
@@ -2833,12 +2854,66 @@ def fix_package(file='stooq.py',package='pandas_datareader'):
|
|
2833
2854
|
print(" Please RESTART your Python kernel before continue to use siat")
|
2834
2855
|
|
2835
2856
|
return
|
2857
|
+
|
2858
|
+
#==============================================================================
|
2859
|
+
if __name__=='__main__':
|
2860
|
+
file='stock_info.pickle'
|
2861
|
+
package='siat'
|
2862
|
+
developer=False
|
2863
|
+
|
2864
|
+
file_position()
|
2865
|
+
|
2866
|
+
def file_position(file='stock_info.pickle',package='siat',mode='read'):
|
2867
|
+
"""
|
2868
|
+
功能:给定文件名file,返回其路径
|
2869
|
+
注意:执行本程序可能需要系统管理员权限,可以系统管理员权限启动Jupyter或Spyder
|
2870
|
+
|
2871
|
+
改进:建立一个Excel文件,记录需要修复的文件和包,例如:
|
2872
|
+
file package
|
2873
|
+
stooq.py pandas_datareader
|
2874
|
+
bond_zh_sina.py akshare
|
2875
|
+
|
2876
|
+
"""
|
2877
|
+
#判断操作系统
|
2878
|
+
import sys; czxt=sys.platform
|
2879
|
+
if czxt in ['win32','win64']:
|
2880
|
+
os='windows'
|
2881
|
+
elif czxt in ['darwin']: #MacOSX
|
2882
|
+
os='mac'
|
2883
|
+
elif czxt in ['linux']: #linux
|
2884
|
+
os='linux'
|
2885
|
+
else:
|
2886
|
+
os='windows'
|
2887
|
+
|
2888
|
+
#目标地址
|
2889
|
+
cmdstr1='import '+package
|
2890
|
+
exec(cmdstr1) #无返回值地执行字符串代码
|
2891
|
+
#import pandas_datareader
|
2892
|
+
#objpath=pandas_datareader.__path__[0]
|
2893
|
+
cmdstr2=package+'.__path__[0]'
|
2894
|
+
objpath=eval(cmdstr2) #有返回值地执行字符串代码
|
2895
|
+
|
2896
|
+
if os == 'windows':
|
2897
|
+
objpath1=objpath.replace("\\",'/')
|
2898
|
+
objfile=objpath1+'/'+file
|
2899
|
+
else:
|
2900
|
+
objpath1=objpath
|
2901
|
+
objfile=objpath1+'/'+file
|
2836
2902
|
|
2903
|
+
if mode=='read':
|
2904
|
+
with open(objfile,'rb') as test:
|
2905
|
+
df = pickle.load(test)
|
2906
|
+
return df
|
2907
|
+
else:
|
2908
|
+
return objfile
|
2909
|
+
#==============================================================================
|
2910
|
+
|
2911
|
+
|
2837
2912
|
#==============================================================================
|
2838
2913
|
#==============================================================================
|
2839
2914
|
|
2840
|
-
def df_preprocess(dfs,measure,axhline_label,x_label,y_label,
|
2841
|
-
preprocess='scaling',scaling_option='
|
2915
|
+
def df_preprocess(dfs,measure,axhline_label,x_label,y_label, \
|
2916
|
+
preprocess='scaling',scaling_option='change%'):
|
2842
2917
|
"""
|
2843
2918
|
功能:对于dfs中的数据进行预处理变换,以便克服数量级压制现象更好地展现多条曲线的趋势
|
2844
2919
|
"""
|
@@ -2854,9 +2929,6 @@ def df_preprocess(dfs,measure,axhline_label,x_label,y_label,lang='Chinese', \
|
|
2854
2929
|
meanlist=[]
|
2855
2930
|
for c in collist:
|
2856
2931
|
|
2857
|
-
# 去掉缺失值
|
2858
|
-
#dfs2[c].dropna(inplace=True)
|
2859
|
-
|
2860
2932
|
if preprocess1 == 'standardize': #标准化
|
2861
2933
|
cmean=dfs2[c].mean()
|
2862
2934
|
cstd=dfs2[c].std()
|
@@ -2881,16 +2953,12 @@ def df_preprocess(dfs,measure,axhline_label,x_label,y_label,lang='Chinese', \
|
|
2881
2953
|
return None
|
2882
2954
|
if scaling_option == 'mean':
|
2883
2955
|
cmean=dfs2[c].mean() #使用均值
|
2884
|
-
|
2885
|
-
|
2886
|
-
else:
|
2887
|
-
scalingOptionText='均值'
|
2956
|
+
scalingOptionText=text_lang('均值','mean value')
|
2957
|
+
|
2888
2958
|
if scaling_option == 'min':
|
2889
2959
|
cmean=dfs2[c].min() #使用最小值
|
2890
|
-
|
2891
|
-
|
2892
|
-
else:
|
2893
|
-
scalingOptionText='最小值'
|
2960
|
+
scalingOptionText=text_lang('最小值','min value')
|
2961
|
+
|
2894
2962
|
#if scaling_option == 'start':
|
2895
2963
|
if scaling_option in ['start','percentage','change%']:
|
2896
2964
|
# 从头寻找第一个非空数值
|
@@ -2901,11 +2969,13 @@ def df_preprocess(dfs,measure,axhline_label,x_label,y_label,lang='Chinese', \
|
|
2901
2969
|
else:
|
2902
2970
|
cmean=dfs2[c][n] #使用第一个非空值
|
2903
2971
|
break
|
2904
|
-
|
2905
|
-
if
|
2906
|
-
scalingOptionText='starting value'
|
2972
|
+
|
2973
|
+
if scaling_option in ['start']:
|
2974
|
+
scalingOptionText=text_lang('起点值','starting value')
|
2975
|
+
elif scaling_option in ['percentage']:
|
2976
|
+
scalingOptionText=text_lang('百分比','percentage')
|
2907
2977
|
else:
|
2908
|
-
scalingOptionText='
|
2978
|
+
scalingOptionText=text_lang('变化率%','change%')
|
2909
2979
|
|
2910
2980
|
meanlist=meanlist+[cmean]
|
2911
2981
|
|
@@ -2941,6 +3011,7 @@ def df_preprocess(dfs,measure,axhline_label,x_label,y_label,lang='Chinese', \
|
|
2941
3011
|
dfs2[c]=dfs2[c].apply(lambda x: (x/cfactor-1)*100)
|
2942
3012
|
|
2943
3013
|
#设置中英文的脚注和纵轴标记
|
3014
|
+
lang=check_language()
|
2944
3015
|
if lang == 'English':
|
2945
3016
|
if preprocess1 == 'standardize':
|
2946
3017
|
std_notes="Note: for ease of comparison, data are standardized "
|
@@ -2993,7 +3064,7 @@ def df_preprocess(dfs,measure,axhline_label,x_label,y_label,lang='Chinese', \
|
|
2993
3064
|
elif scaling_option == 'change%':
|
2994
3065
|
std_notes="注释:为突出变化趋势,图中数值为相对期间起点的增减百分比"
|
2995
3066
|
#measure_suffix='(增/减%)'
|
2996
|
-
measure_suffix='(
|
3067
|
+
measure_suffix='(涨跌幅度%)'
|
2997
3068
|
axhline_label='零线' #可以在security_trend中使用critical_value选项指定水平线位置,默认0
|
2998
3069
|
#axhline_value=0
|
2999
3070
|
|
@@ -3195,48 +3266,21 @@ def start_end_preprocess(start,end='today'):
|
|
3195
3266
|
# 检查日期:开始日期
|
3196
3267
|
start=start.lower()
|
3197
3268
|
|
3198
|
-
"""
|
3199
|
-
if start in ['default','mrm','l1m']: # 默认近一个月
|
3200
|
-
fromdate=date_adjust(todate,adjust=-31-7) #多几天有利于绘图坐标标示
|
3201
|
-
elif start in ['l2m']: # 近2个月
|
3202
|
-
fromdate=date_adjust(todate,adjust=-31*2-14)
|
3203
|
-
elif start in ['mrq','l3m']: # 近三个月
|
3204
|
-
fromdate=date_adjust(todate,adjust=-31*3-16)
|
3205
|
-
elif start in ['l6m','mrh']: # 近6个月
|
3206
|
-
fromdate=date_adjust(todate,adjust=-31*6-16)
|
3207
|
-
elif start in ['mry','l12m']: # 近一年
|
3208
|
-
fromdate=date_adjust(todate,adjust=-366-16)
|
3209
|
-
elif start in ['l2y']: # 近两年以来
|
3210
|
-
fromdate=date_adjust(todate,adjust=-366*2-15)
|
3211
|
-
elif start in ['l3y']: # 近三年以来
|
3212
|
-
fromdate=date_adjust(todate,adjust=-366*3-14)
|
3213
|
-
elif start in ['l5y']: # 近五年以来
|
3214
|
-
fromdate=date_adjust(todate,adjust=-366*5-13)
|
3215
|
-
elif start in ['l8y']: # 近八年以来
|
3216
|
-
fromdate=date_adjust(todate,adjust=-366*8-11)
|
3217
|
-
elif start in ['l10y']: # 近十年以来
|
3218
|
-
fromdate=date_adjust(todate,adjust=-366*10-9)
|
3219
|
-
elif start in ['l20y']: # 近20年以来
|
3220
|
-
fromdate=date_adjust(todate,adjust=-366*20-1)
|
3221
|
-
elif start in ['l30y']: # 近30年以来
|
3222
|
-
fromdate=date_adjust(todate,adjust=-366*30)
|
3223
|
-
elif start in ['ytd']: # 今年以来
|
3224
|
-
fromdate=str(todaydt.year-1)+'-12-1'
|
3225
|
-
else:
|
3226
|
-
validdate,fromdate=check_date2(start)
|
3227
|
-
if not validdate:
|
3228
|
-
print(" #Warning(security_trend): invalid date for",start,"/b, reset to MRM")
|
3229
|
-
fromdate=date_adjust(todate,adjust=-31-16)
|
3230
|
-
"""
|
3231
3269
|
if start in ['default','mrm','l1m']: # 默认近一个月
|
3232
3270
|
fromdate=date_adjust2(todate,adjust_month=-1,adjust_day=-1) #有利于绘图横坐标日期标示
|
3271
|
+
elif start in ['mrw','l1w']: # 近1个周
|
3272
|
+
fromdate=date_adjust2(todate,adjust_month=0,adjust_day=-7-1)
|
3273
|
+
elif start in ['lhm','l2w']: # 近2个周
|
3274
|
+
fromdate=date_adjust2(todate,adjust_month=0,adjust_day=-7*2-1)
|
3275
|
+
elif start in ['l3w']: # 近3个周
|
3276
|
+
fromdate=date_adjust2(todate,adjust_month=0,adjust_day=-7*3-1)
|
3233
3277
|
elif start in ['l2m']: # 近2个月
|
3234
3278
|
fromdate=date_adjust2(todate,adjust_month=-2,adjust_day=-1)
|
3235
3279
|
elif start in ['mrq','l3m']: # 近三个月
|
3236
3280
|
fromdate=date_adjust2(todate,adjust_month=-3,adjust_day=-1)
|
3237
3281
|
elif start in ['l6m','mrh']: # 近6个月
|
3238
3282
|
fromdate=date_adjust2(todate,adjust_month=-6,adjust_day=-1)
|
3239
|
-
elif start in ['mry','l12m']: # 近一年
|
3283
|
+
elif start in ['mry','l12m','l1y']: # 近一年
|
3240
3284
|
fromdate=date_adjust2(todate,adjust_year=-1,to_prev_month_end=True)
|
3241
3285
|
elif start in ['l2y']: # 近两年以来
|
3242
3286
|
fromdate=date_adjust2(todate,adjust_year=-2,to_prev_month_end=True)
|
@@ -3267,6 +3311,337 @@ def start_end_preprocess(start,end='today'):
|
|
3267
3311
|
|
3268
3312
|
return fromdate,todate
|
3269
3313
|
|
3314
|
+
#==============================================================================
|
3315
|
+
if __name__=='__main__':
|
3316
|
+
text_cn="这是中文"
|
3317
|
+
text_en="This is in English"
|
3318
|
+
|
3319
|
+
set_language('English')
|
3320
|
+
set_language('Chinese')
|
3321
|
+
|
3322
|
+
text_lang(text_cn, text_en)
|
3323
|
+
|
3324
|
+
def text_lang(text_cn, text_en):
|
3325
|
+
"""
|
3326
|
+
功能:检测当前语言环境,若为中文返回text_cn,否则返回text_cn
|
3327
|
+
"""
|
3328
|
+
lang=check_language()
|
3329
|
+
|
3330
|
+
if lang == 'Chinese':
|
3331
|
+
result=text_cn
|
3332
|
+
else:
|
3333
|
+
result=text_en
|
3334
|
+
|
3335
|
+
return result
|
3336
|
+
|
3337
|
+
#==============================================================================
|
3338
|
+
if __name__=='__main__':
|
3339
|
+
df,_=get_price_1ticker('sh010504',fromdate='2024-1-1',todate='2024-4-6',fill=False)
|
3340
|
+
|
3341
|
+
def df_have_data(df):
|
3342
|
+
"""
|
3343
|
+
功能:判断df内是否有数据
|
3344
|
+
返回:有数据-Found,df存在但无数据-Empty,其余-None
|
3345
|
+
"""
|
3346
|
+
found=None
|
3347
|
+
if df is None:
|
3348
|
+
found='None'
|
3349
|
+
elif len(df)==0:
|
3350
|
+
found='Empty'
|
3351
|
+
else:
|
3352
|
+
found='Found'
|
3353
|
+
|
3354
|
+
return found
|
3355
|
+
|
3356
|
+
#==============================================================================
|
3357
|
+
if __name__=='__main__':
|
3358
|
+
df,_=get_price_1ticker('sz149976',fromdate='2024-1-1',todate='2024-4-6',fill=False)
|
3359
|
+
colname='Close'
|
3360
|
+
extend_business_date=False
|
3361
|
+
|
3362
|
+
df4=df_fill_extend(df,colname='Close',extend_business_date=False)
|
3363
|
+
|
3364
|
+
def df_fill_extend(df,colname='Close',extend_business_date=False):
|
3365
|
+
"""
|
3366
|
+
功能:对df进行填充
|
3367
|
+
colname:基于此判断是否为空,默认为'Close'
|
3368
|
+
extend_business_date:False=仅对df现有值进行填充,
|
3369
|
+
True=对于现有开始结束日期之间的所有非周末日期进行扩展后填充
|
3370
|
+
"""
|
3371
|
+
import numpy as np
|
3372
|
+
|
3373
|
+
df1=df.copy()
|
3374
|
+
#仅对现有数据中的缺失值进行填充
|
3375
|
+
if not extend_business_date:
|
3376
|
+
df1['filled']=df1[colname].apply(lambda x: True if np.isnan(x) else False)
|
3377
|
+
df4=df1.ffill(axis=0) #从开始向尾部填充
|
3378
|
+
#df5=df4.bfill(axis=0) #从尾部向开始填充,容易对后续的分析结果造成误导,慎用!
|
3379
|
+
else:
|
3380
|
+
fromdate=df1.head(1).index[0].strftime('%Y-%m-%d')
|
3381
|
+
todate=df1.tail(1).index[0].strftime('%Y-%m-%d')
|
3382
|
+
|
3383
|
+
df2dt=pd.bdate_range(start=fromdate,end=todate)
|
3384
|
+
df2dt=pd.to_datetime(df2dt)
|
3385
|
+
df2=pd.DataFrame(index=df2dt)
|
3386
|
+
df3=pd.merge(df2,df1,how='outer',left_index=True,right_index=True)
|
3387
|
+
|
3388
|
+
df3['filled']=df3[colname].apply(lambda x: True if np.isnan(x) else False)
|
3389
|
+
df4=df3.ffill(axis=0) #从开始向尾部填充
|
3390
|
+
#df5=df4.bfill(axis=0) #从尾部向开始填充
|
3391
|
+
|
3392
|
+
return df4
|
3393
|
+
|
3394
|
+
#==============================================================================
|
3395
|
+
if __name__=='__main__':
|
3396
|
+
url="https://finance.yahoo.com"
|
3397
|
+
url="https://finance.sina.com.cn"
|
3398
|
+
|
3399
|
+
test_website(url)
|
3400
|
+
|
3401
|
+
def test_website(url):
|
3402
|
+
"""
|
3403
|
+
功能:测试一个网址是否可访问
|
3404
|
+
"""
|
3405
|
+
import requests
|
3406
|
+
try:
|
3407
|
+
response = requests.get(url)
|
3408
|
+
if response.status_code == 200:
|
3409
|
+
#print(f"{url} is accessible.")
|
3410
|
+
return True
|
3411
|
+
else:
|
3412
|
+
#print(f"{url} is not accessible. Status code: {response.status_code}")
|
3413
|
+
return False
|
3414
|
+
except requests.exceptions.RequestException:
|
3415
|
+
#print(f"{url} is not accessible. Network error occurred.")
|
3416
|
+
return False
|
3417
|
+
|
3418
|
+
if __name__=='__main__':
|
3419
|
+
test_yahoo_finance()
|
3420
|
+
|
3421
|
+
def test_yahoo_finance():
|
3422
|
+
url="https://finance.yahoo.com"
|
3423
|
+
return test_website(url)
|
3424
|
+
|
3425
|
+
#==============================================================================
|
3426
|
+
if __name__=='__main__':
|
3427
|
+
check_os()
|
3428
|
+
|
3429
|
+
def check_os():
|
3430
|
+
"""
|
3431
|
+
功能:检测操作系统的类型
|
3432
|
+
"""
|
3433
|
+
import platform
|
3434
|
+
system = platform.system()
|
3435
|
+
if system == "Windows":
|
3436
|
+
return "Windows"
|
3437
|
+
elif system == "Linux":
|
3438
|
+
return "Linux"
|
3439
|
+
elif system == "Darwin":
|
3440
|
+
return "Mac OSX"
|
3441
|
+
else:
|
3442
|
+
return "Unknown OS"
|
3443
|
+
|
3444
|
+
#==============================================================================
|
3445
|
+
if __name__=='__main__':
|
3446
|
+
check_python_version()
|
3447
|
+
|
3448
|
+
def check_python_version():
|
3449
|
+
"""
|
3450
|
+
功能:检测Python的版本号
|
3451
|
+
"""
|
3452
|
+
import sys
|
3453
|
+
python_version = sys.version_info
|
3454
|
+
ver=f"{python_version.major}.{python_version.minor}.{python_version.micro}"
|
3455
|
+
return ver
|
3456
|
+
|
3457
|
+
#==============================================================================
|
3458
|
+
if __name__=='__main__':
|
3459
|
+
ticker='AAPL'
|
3460
|
+
fromdate='2011-1-1'
|
3461
|
+
todate='2020-12-31'
|
3462
|
+
retry_count=3
|
3463
|
+
pause=1
|
3464
|
+
|
3465
|
+
ticker='ABCD'
|
3466
|
+
|
3467
|
+
ticker=['AAPL','MSFT']
|
3468
|
+
ticker=['AAPL','MSFT','ABCD']
|
3469
|
+
|
3470
|
+
ticker=['600011.SS']
|
3471
|
+
fromdate='2020-1-1'
|
3472
|
+
todate='2020-6-30'
|
3473
|
+
|
3474
|
+
def upper_ticker(ticker):
|
3475
|
+
"""
|
3476
|
+
功能:改成大写,字符串或列表
|
3477
|
+
"""
|
3478
|
+
if isinstance(ticker,str):
|
3479
|
+
return ticker.upper()
|
3480
|
+
elif isinstance(ticker,list):
|
3481
|
+
tlist=[]
|
3482
|
+
for t in ticker:
|
3483
|
+
try:
|
3484
|
+
tupper=t.upper()
|
3485
|
+
except:
|
3486
|
+
tupper=t
|
3487
|
+
tlist=tlist+[tupper]
|
3488
|
+
return tlist
|
3489
|
+
|
3490
|
+
|
3491
|
+
#==============================================================================
|
3492
|
+
if __name__=='__main__':
|
3493
|
+
ticker='600519.SS'
|
3494
|
+
ticker=['600519.SS','000858.SZ']
|
3495
|
+
ticker=['600519.SS','000858.SZ',pf]
|
3496
|
+
|
3497
|
+
ticker_type='auto'
|
3498
|
+
ticker_type='bond'
|
3499
|
+
ticker_type=['auto','bond']
|
3500
|
+
ticker_type=['xyz','bond']
|
3501
|
+
|
3502
|
+
ticker_type_preprocess_1str(ticker,ticker_type)
|
3503
|
+
|
3504
|
+
def ticker_type_preprocess_1str(ticker,ticker_type='auto'):
|
3505
|
+
"""
|
3506
|
+
功能:根据ticker情况(单个原生证券)处理ticker_type,使之与ticker对应
|
3507
|
+
"""
|
3508
|
+
if isinstance(ticker,str):
|
3509
|
+
if isinstance(ticker_type,str):
|
3510
|
+
ticker_type9=ticker_type
|
3511
|
+
if isinstance(ticker_type,list):
|
3512
|
+
if len(ticker_type) >= 1:
|
3513
|
+
ticker_type9=ticker_type[0]
|
3514
|
+
else:
|
3515
|
+
ticker_type9='auto'
|
3516
|
+
else:
|
3517
|
+
ticker_type9=ticker_type
|
3518
|
+
|
3519
|
+
if ticker_type9 not in ['auto','stock','fund','bond']:
|
3520
|
+
ticker_type9='auto'
|
3521
|
+
|
3522
|
+
return ticker_type9
|
3523
|
+
|
3524
|
+
if __name__=='__main__':
|
3525
|
+
pf={'Market':('China','000001.SS','股债基组合'),'600519.SS':50,'sh018003':150,'sh010504':300}
|
3526
|
+
ticker=['600519.SS','000858.SZ','000002.SZ']
|
3527
|
+
ticker=['600519.SS','000858.SZ',pf]
|
3528
|
+
|
3529
|
+
ticker_type='auto'
|
3530
|
+
ticker_type='bond'
|
3531
|
+
ticker_type=['auto','bond']
|
3532
|
+
ticker_type=['xyz','bond']
|
3533
|
+
|
3534
|
+
ticker_type_preprocess_mstr(ticker,ticker_type)
|
3535
|
+
|
3536
|
+
def ticker_type_preprocess_mstr(ticker,ticker_type='auto'):
|
3537
|
+
"""
|
3538
|
+
功能:根据ticker情况(多个原生证券)处理ticker_type,使之与ticker对应
|
3539
|
+
"""
|
3540
|
+
if isinstance(ticker,list):
|
3541
|
+
if isinstance(ticker_type,str):
|
3542
|
+
ticker_type8=[ticker_type]*len(ticker)
|
3543
|
+
|
3544
|
+
if isinstance(ticker_type,list):
|
3545
|
+
if len(ticker) > len(ticker_type):
|
3546
|
+
ticker_type8=ticker_type+[ticker_type[-1]]*(len(ticker)-len(ticker_type))
|
3547
|
+
else:
|
3548
|
+
ticker_type8=ticker_type
|
3549
|
+
|
3550
|
+
ticker_type9=[]
|
3551
|
+
for tt in ticker_type8:
|
3552
|
+
if tt not in ['auto','stock','fund','bond']:
|
3553
|
+
tt='auto'
|
3554
|
+
ticker_type9=ticker_type9+[tt]
|
3555
|
+
|
3556
|
+
else:
|
3557
|
+
ticker_type9=ticker_type
|
3558
|
+
|
3559
|
+
return ticker_type9
|
3560
|
+
|
3561
|
+
if __name__=='__main__':
|
3562
|
+
ticker={'Market':('China','000001.SS','股债基组合'),'600519.SS':50,'sh018003':150,'sh010504':300}
|
3563
|
+
|
3564
|
+
ticker_type='auto'
|
3565
|
+
ticker_type='bond'
|
3566
|
+
ticker_type=['auto','bond']
|
3567
|
+
ticker_type=['xyz','bond']
|
3568
|
+
|
3569
|
+
ticker_type_preprocess_1portfolio(ticker,ticker_type)
|
3570
|
+
|
3571
|
+
def ticker_type_preprocess_1portfolio(ticker,ticker_type='auto'):
|
3572
|
+
"""
|
3573
|
+
功能:根据ticker情况(单个投资组合)处理ticker_type,使之与ticker对应
|
3574
|
+
"""
|
3575
|
+
if isinstance(ticker,dict):
|
3576
|
+
_,_,tickerlist,_=decompose_portfolio(ticker)
|
3577
|
+
if len(tickerlist)==1:
|
3578
|
+
ticker_type9=ticker_type_preprocess_1str(tickerlist[0],ticker_type)
|
3579
|
+
else:
|
3580
|
+
ticker_type9=ticker_type_preprocess_mstr(tickerlist,ticker_type)
|
3581
|
+
else:
|
3582
|
+
ticker_type9=ticker_type
|
3583
|
+
|
3584
|
+
return ticker_type9
|
3585
|
+
|
3586
|
+
if __name__=='__main__':
|
3587
|
+
pf={'Market':('China','000001.SS','股债基组合'),'600519.SS':50,'sh018003':150,'sh010504':300}
|
3588
|
+
ticker='600519.SS'
|
3589
|
+
ticker=['600519.SS','000858.SZ','000002.SZ']
|
3590
|
+
ticker={'Market':('China','000001.SS','股债基组合'),'600519.SS':50,'sh018003':150,'sh010504':300}
|
3591
|
+
|
3592
|
+
ticker=['600519.SS','000858.SZ',pf]
|
3593
|
+
|
3594
|
+
ticker_type='auto'
|
3595
|
+
ticker_type='bond'
|
3596
|
+
ticker_type=['auto','bond']
|
3597
|
+
ticker_type=['xyz','bond']
|
3598
|
+
|
3599
|
+
ticker_type_preprocess_mticker_mixed(ticker,ticker_type)
|
3600
|
+
|
3601
|
+
def ticker_type_preprocess_mticker_mixed(ticker,ticker_type='auto'):
|
3602
|
+
"""
|
3603
|
+
功能:根据ticker(可为列表,列表中可含有投资组合)情况处理ticker_type,使之与ticker对应
|
3604
|
+
"""
|
3605
|
+
#单个证券,非投资组合
|
3606
|
+
if isinstance(ticker,str):
|
3607
|
+
ticker_type9=ticker_type_preprocess_1str(ticker,ticker_type)
|
3608
|
+
return ticker_type9
|
3609
|
+
|
3610
|
+
#单个证券,投资组合
|
3611
|
+
if isinstance(ticker,dict):
|
3612
|
+
ticker_type9=ticker_type_preprocess_1portfolio(ticker,ticker_type)
|
3613
|
+
return ticker_type9
|
3614
|
+
|
3615
|
+
#混合列表
|
3616
|
+
if isinstance(ticker,list):
|
3617
|
+
if isinstance(ticker_type,str):
|
3618
|
+
ticker_type8=[ticker_type]*len(ticker)
|
3619
|
+
if isinstance(ticker_type,list):
|
3620
|
+
if len(ticker) > len(ticker_type):
|
3621
|
+
ticker_type8=ticker_type+[ticker_type[-1]]*(len(ticker)-len(ticker_type))
|
3622
|
+
else:
|
3623
|
+
ticker_type8=ticker_type
|
3624
|
+
|
3625
|
+
ticker_type9=[]
|
3626
|
+
for t in ticker:
|
3627
|
+
pos=ticker.index(t)
|
3628
|
+
tt8=ticker_type8[pos]
|
3629
|
+
tt9=tt8
|
3630
|
+
|
3631
|
+
if isinstance(t,str):
|
3632
|
+
tt9=ticker_type_preprocess_1str(t,tt8)
|
3633
|
+
|
3634
|
+
if isinstance(t,dict):
|
3635
|
+
tt9=ticker_type_preprocess_1portfolio(t,tt8)
|
3636
|
+
|
3637
|
+
ticker_type9=ticker_type9+[tt9]
|
3638
|
+
else:
|
3639
|
+
ticker_type9=ticker_type
|
3640
|
+
|
3641
|
+
return ticker_type9
|
3642
|
+
|
3643
|
+
|
3644
|
+
#==============================================================================
|
3270
3645
|
#==============================================================================
|
3271
3646
|
#==============================================================================
|
3272
3647
|
|