siat 3.2.4__py3-none-any.whl → 3.2.10__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/stock_technical.py CHANGED
@@ -90,7 +90,7 @@ if __name__ =="__main__":
90
90
 
91
91
  BIAS_days=[6,12,24]
92
92
 
93
- CCI_days=14
93
+ CCI_day=14; CCI_madays=[5,20]
94
94
 
95
95
  WR_days=[10,6]
96
96
 
@@ -161,32 +161,51 @@ if __name__ =="__main__":
161
161
 
162
162
 
163
163
 
164
- def calc_technical(df,start,end, \
165
- RSI_days=14, \
166
- OBV_days=5, \
167
-
168
- MA_days=[5,20], \
169
- MACD_fastperiod=12,MACD_slowperiod=26,MACD_signalperiod=9, \
170
-
171
- KDJ_fastk_period=9,KDJ_slowk_period=5,KDJ_slowk_matype=1, \
172
- KDJ_slowd_period=5,KDJ_slowd_matype=1, \
173
-
174
- VOL_fastperiod=5,VOL_slowperiod=10, \
175
- PSY_days=12, \
176
- ARBR_days=26, \
177
- CR_day=16,CR_madays=[5,10,20], \
178
- EMV_day=14,EMV_madays=9, \
179
- BULL_days=20,BULL_nbdevup=2,BULL_nbdevdn=2,BULL_matype=0, \
180
- DMA_fastperiod=10,DMA_slowperiod=50,DMA_madays=10, \
181
- TRIX_day=12,TRIX_madays=20, \
182
- BIAS_days=[6,12,24], \
183
- CCI_days=14, \
184
- WR_days=[10,6], \
185
- ROC_day=12,ROC_madays=6, \
186
- DMI_DIdays=14,DMI_ADXdays=6, \
187
-
188
- indicator='Close', \
189
- more_details=False):
164
+ def calc_technical(df,start,end,technical='MACD', \
165
+
166
+ RSI_days=[14], \
167
+ OBV_days=[5], \
168
+
169
+ MA_days=[5,20],EMA_days=[5,20], \
170
+ MACD_fastperiod=12,MACD_slowperiod=26,MACD_signalperiod=9, \
171
+
172
+ KDJ_fastk_period=9,KDJ_slowk_period=5,KDJ_slowk_matype=1,KDJ_slowd_period=5,KDJ_slowd_matype=1, \
173
+
174
+ VOL_fastperiod=5,VOL_slowperiod=10, \
175
+ PSY_days=[12], \
176
+ ARBR_days=[26], \
177
+ CR_day=16,CR_madays=[5,10,20], \
178
+ EMV_day=14,EMV_madays=[9], \
179
+
180
+ BULL_day=20,BULL_nbdevup=2,BULL_nbdevdn=2,BULL_matype=0, \
181
+
182
+ DMA_fastperiod=10,DMA_slowperiod=50,DMA_madays=[10], \
183
+
184
+ TRIX_day=12,TRIX_madays=[20], \
185
+ BIAS_days=[6,12,24], \
186
+ CCI_day=14,CCI_madays=[5,20], \
187
+ WR_days=[10,6], \
188
+ ROC_day=12,ROC_madays=[6], \
189
+ DMI_DIdays=[14],DMI_ADXdays=[6], \
190
+
191
+ MFI_day=14,MFI_madays=[14], \
192
+ MOM_day=10,MOM_madays=[10], \
193
+
194
+ #需要显示SAR
195
+ SAR_day=4,SAR_madays=[5,20], \
196
+
197
+ #需要显示BETA
198
+ BETA_day=5,BETA_madays=[5,20], \
199
+
200
+ #需要显示TSF
201
+ TSF_day=14,TSF_madays=[5,20], \
202
+
203
+ #需要显示AD
204
+ AD_day=26,AD_madays=[5,20], \
205
+
206
+ #不建议使用复权价,因为最高最低价和开盘价没有复权价!
207
+ indicator='Close', \
208
+ more_details=False):
190
209
  """
191
210
  功能:计算股票的技术分析指标
192
211
  输入:df,四种股价Open/Close/High/Low,成交量Volume
@@ -211,6 +230,9 @@ def calc_technical(df,start,end, \
211
230
  talib_install_method()
212
231
  return None
213
232
 
233
+ #用于对比,检查是否有计算结果的指标加入
234
+ dfcols_original=list(df)
235
+
214
236
  #=========== RSI,相对强弱指标Relative Strength Index
215
237
  """
216
238
  计算公式:RSI有两种计算方法:
@@ -228,11 +250,13 @@ def calc_technical(df,start,end, \
228
250
  30-50 弱 观望,谨慎买入
229
251
  0-30 极弱 买入
230
252
  """
231
- if not isinstance(RSI_days,list):
232
- RSI_days=[RSI_days]
233
- for d in RSI_days:
234
- df['rsi'+str(d)] = talib.RSI(df[indicator], timeperiod=d)
235
- #注意:rsi1没有意义
253
+ if technical=='RSI':
254
+
255
+ if not isinstance(RSI_days,list):
256
+ RSI_days=[RSI_days]
257
+ for d in RSI_days:
258
+ df['rsi'+str(d)] = talib.RSI(df[indicator], timeperiod=d)
259
+ #注意:rsi1没有意义
236
260
 
237
261
  #=========== OBV:能量潮
238
262
  """
@@ -263,15 +287,17 @@ def calc_technical(df,start,end, \
263
287
  因此,对于那些达到涨跌停板的股票,OBV指标也无法正常发挥作用。
264
288
 
265
289
  """
266
- df['obv'] = talib.OBV(df[indicator],df['Volume'])
267
-
268
- if not isinstance(OBV_days,list):
269
- OBV_days=[OBV_days]
270
- for d in OBV_days:
271
- df['obv_ma'+str(d)] = talib.MA(df['obv'],timeperiod=d)
290
+ if technical=='OBV':
272
291
 
273
- if not more_details:
274
- df.drop(columns = ['obv'],inplace=True)
292
+ df['obv'] = talib.OBV(df[indicator],df['Volume'])
293
+
294
+ if not isinstance(OBV_days,list):
295
+ OBV_days=[OBV_days]
296
+ for d in OBV_days:
297
+ df['obv_ma'+str(d)] = talib.MA(df['obv'],timeperiod=d)
298
+
299
+ if not more_details:
300
+ df.drop(columns = ['obv'],inplace=True)
275
301
 
276
302
  #=========== MA: 简单、加权移动平均
277
303
  """
@@ -282,13 +308,22 @@ def calc_technical(df,start,end, \
282
308
  一般来说,现行价格在平均价之上,意味着市场买力(需求)较大,行情看好;
283
309
  反之,行情价在平均价之下,则意味着供过于求,卖压显然较重,行情看淡。
284
310
  """
285
- if not isinstance(MA_days,list):
286
- MA_days=[MA_days]
311
+ if technical=='MA':
287
312
 
288
- for d in MA_days:
289
- df['ma'+str(d)] = talib.MA(df[indicator],timeperiod=d)
290
- df['ema'+str(d)] = talib.EMA(df[indicator],timeperiod=d)
313
+ if not isinstance(MA_days,list):
314
+ MA_days=[MA_days]
315
+
316
+ for d in MA_days:
317
+ df['ma'+str(d)] = talib.MA(df[indicator],timeperiod=d)
318
+
319
+ if technical=='EMA':
291
320
 
321
+ if not isinstance(EMA_days,list):
322
+ EMA_days=[EMA_days]
323
+
324
+ for d in EMA_days:
325
+ df['ema'+str(d)] = talib.EMA(df[indicator],timeperiod=d)
326
+
292
327
  #=========== MACD:指数平滑异同平均线
293
328
  """
294
329
  计算方法:快速时间窗口设为12日,慢速时间窗口设为26日,DIF参数设为9日
@@ -317,10 +352,12 @@ def calc_technical(df,start,end, \
317
352
  3. MACD绿转红:MACD值由负变正,市场由空头转为多头。
318
353
  4. MACD红转绿:MACD值由正变负,市场由多头转为空头。
319
354
  """
320
- df['DIF'],df['DEA'],df['MACD']=talib.MACD(df[indicator], \
321
- fastperiod=MACD_fastperiod, \
322
- slowperiod=MACD_slowperiod, \
323
- signalperiod=MACD_signalperiod)
355
+ if technical=='MACD':
356
+
357
+ df['DIF'],df['DEA'],df['MACD']=talib.MACD(df[indicator], \
358
+ fastperiod=MACD_fastperiod, \
359
+ slowperiod=MACD_slowperiod, \
360
+ signalperiod=MACD_signalperiod)
324
361
 
325
362
  #=========== KDJ: 随机指标
326
363
  """
@@ -339,13 +376,15 @@ def calc_technical(df,start,end, \
339
376
  多头区域,空头区域
340
377
  金叉,死叉
341
378
  """
342
- df['kdj_k'],df['kdj_d'] = talib.STOCH(df['High'],df['Low'],df['Close'], \
343
- fastk_period=KDJ_fastk_period,
344
- slowk_period=KDJ_slowk_period,
345
- slowk_matype=KDJ_slowk_matype,
346
- slowd_period=KDJ_slowd_period,
347
- slowd_matype=KDJ_slowd_matype)
348
- df['kdj_j'] = 3*df['kdj_k'] - 2*df['kdj_d']
379
+ if technical=='KDJ':
380
+
381
+ df['kdj_k'],df['kdj_d'] = talib.STOCH(df['High'],df['Low'],df[indicator], \
382
+ fastk_period=KDJ_fastk_period,
383
+ slowk_period=KDJ_slowk_period,
384
+ slowk_matype=KDJ_slowk_matype,
385
+ slowd_period=KDJ_slowd_period,
386
+ slowd_matype=KDJ_slowd_matype)
387
+ df['kdj_j'] = 3*df['kdj_k'] - 2*df['kdj_d']
349
388
 
350
389
  #=========== SAR: 抛物转向
351
390
  """
@@ -368,14 +407,29 @@ def calc_technical(df,start,end, \
368
407
  7)SAR指标基准周期的参数为2,如2日、2周、2月等,其计算周期的参数变动范围为2~8
369
408
  8)SAR指标在股价分析系统的主图上显示为“O”形点状图。
370
409
  """
371
- df['sar'] = talib.SAR(df['High'],df['Low'])
372
-
410
+ if technical=='SAR':
411
+
412
+ df['sar'] = talib.SAR(df['High'],df['Low'])
413
+
414
+ if not isinstance(SAR_madays,list):
415
+ SAR_madays=[SAR_madays]
416
+ for d in SAR_madays:
417
+ df['sar_ma'+str(d)] = df['sar'].rolling(window=d).mean()
418
+
419
+ #需要显示SAR?
420
+ """
421
+ if not more_details:
422
+ #不保留指标本身
423
+ df.drop(columns = ['sar'],inplace=True)
424
+ """
373
425
  #=========== VOL: 成交量
374
426
  """
375
427
  柱状图是成交量,两条曲线是成交量的移动平均
376
428
  """
377
- df['vol'+str(VOL_fastperiod)] = talib.MA(df['Volume'],timeperiod=VOL_fastperiod)
378
- df['vol'+str(VOL_slowperiod)] = talib.MA(df['Volume'],timeperiod=VOL_slowperiod)
429
+ if technical=='VOL':
430
+
431
+ df['vol'+str(VOL_fastperiod)] = talib.MA(df['Volume'],timeperiod=VOL_fastperiod)
432
+ df['vol'+str(VOL_slowperiod)] = talib.MA(df['Volume'],timeperiod=VOL_slowperiod)
379
433
 
380
434
  #=========== PSY: 心理线
381
435
  """
@@ -383,17 +437,19 @@ def calc_technical(df,start,end, \
383
437
  PSY(N) = A/N × 100
384
438
  说明:N为天数,A为在这N天之中股价上涨的天数
385
439
  """
386
- df['ext_0'] = df[indicator]-df[indicator].shift(1)
387
- df['ext_1'] = 0
388
- df.loc[df['ext_0']>0,'ext_1'] = 1
440
+ if technical=='PSY':
389
441
 
390
- if not isinstance(PSY_days,list):
391
- PSY_days=[PSY_days]
392
- for d in PSY_days:
393
- df['ext_2'] = df['ext_1'].rolling(window=d).sum()
394
- df['psy'+str(d)] = (df['ext_2']/float(d))*100
395
-
396
- df.drop(columns = ['ext_0','ext_1','ext_2'],inplace=True)
442
+ df['ext_0'] = df[indicator]-df[indicator].shift(1)
443
+ df['ext_1'] = 0
444
+ df.loc[df['ext_0']>0,'ext_1'] = 1
445
+
446
+ if not isinstance(PSY_days,list):
447
+ PSY_days=[PSY_days]
448
+ for d in PSY_days:
449
+ df['ext_2'] = df['ext_1'].rolling(window=d).sum()
450
+ df['psy'+str(d)] = (df['ext_2']/float(d))*100
451
+
452
+ df.drop(columns = ['ext_0','ext_1','ext_2'],inplace=True)
397
453
 
398
454
  #=========== ARBR: 人气和意愿指标, AR为人气指标,BR为买卖意愿指标
399
455
  """
@@ -403,25 +459,27 @@ def calc_technical(df,start,end, \
403
459
  BR(N) = N日内(H-CY)之和 ÷ N日内(CY-L)之和 × 100
404
460
  说明:H表示当天最高价;L表示当天最低价;CY表示前一交易日的收盘价,N表示设定的时间参数,一般原始参数缺省值为26日
405
461
  """
406
- df['h_o'] = df['High'] - df['Open']
407
- df['o_l'] = df['Open'] - df['Low']
408
-
409
- if not isinstance(ARBR_days,list):
410
- ARBR_days=[ARBR_days]
411
- for d in ARBR_days:
412
- df['h_o_sum'] = df['h_o'].rolling(window=d).sum()
413
- df['o_l_sum'] = df['o_l'].rolling(window=d).sum()
414
- df['ar'+str(d)] = (df['h_o_sum']/df['o_l_sum'])*100
462
+ if technical=='ARBR':
415
463
 
464
+ df['h_o'] = df['High'] - df['Open']
465
+ df['o_l'] = df['Open'] - df['Low']
466
+
467
+ if not isinstance(ARBR_days,list):
468
+ ARBR_days=[ARBR_days]
469
+ for d in ARBR_days:
470
+ df['h_o_sum'] = df['h_o'].rolling(window=d).sum()
471
+ df['o_l_sum'] = df['o_l'].rolling(window=d).sum()
472
+ df['ar'+str(d)] = (df['h_o_sum']/df['o_l_sum'])*100
473
+
474
+
475
+ df['h_c'] = df['High'] - df[indicator]
476
+ df['c_l'] = df[indicator] - df['Low']
477
+ for d in ARBR_days:
478
+ df['h_c_sum'] = df['h_c'].rolling(window=d).sum()
479
+ df['c_l_sum'] = df['c_l'].rolling(window=d).sum()
480
+ df['br'+str(d)] = (df['h_c_sum']/df['c_l_sum'])*100
416
481
 
417
- df['h_c'] = df['High'] - df['Close']
418
- df['c_l'] = df['Close'] - df['Low']
419
- for d in ARBR_days:
420
- df['h_c_sum'] = df['h_c'].rolling(window=d).sum()
421
- df['c_l_sum'] = df['c_l'].rolling(window=d).sum()
422
- df['br'+str(d)] = (df['h_c_sum']/df['c_l_sum'])*100
423
-
424
- df.drop(columns = ['h_o','o_l','h_o_sum','o_l_sum','h_c','c_l','h_c_sum','c_l_sum'],inplace=True)
482
+ df.drop(columns = ['h_o','o_l','h_o_sum','o_l_sum','h_c','c_l','h_c_sum','c_l_sum'],inplace=True)
425
483
 
426
484
  #=========== CR: 带状能力线或中间意愿指标
427
485
  """
@@ -436,22 +494,22 @@ def calc_technical(df,start,end, \
436
494
  说明:N为设定的时间周期参数,一般原始参数日设定为26日
437
495
  3)计算CR值在不同时间周期内的移动平均值:这三条移动平均曲线分别为MA1 MA2 MA3,时间周期分别为5日 10日 20日
438
496
  """
439
- df['m_price'] = (df['High'] + df['Low'])/2
440
- df['h_m'] = df['High']-df['m_price'].shift(1)
441
- df['m_l'] = df['m_price'].shift(1)-df['Low']
442
-
443
- df['h_m_sum'] = df['h_m'].rolling(window=CR_day).sum()
444
- df['m_l_sum'] = df['m_l'].rolling(window=CR_day).sum()
445
- df['cr'] = (df['h_m_sum']/df['m_l_sum'])*100
446
-
447
- for d in CR_madays:
448
- df['cr_ma'+str(d)] = talib.MA(df['cr'],timeperiod=d)
497
+ if technical=='CR':
449
498
 
450
- if more_details:
451
- #保留cr
452
- df.drop(columns = ['m_price','h_m','m_l','h_m_sum','m_l_sum'],inplace=True)
453
- else:
454
- df.drop(columns = ['m_price','h_m','m_l','h_m_sum','m_l_sum','cr'],inplace=True)
499
+ df['m_price'] = (df['High'] + df['Low'])/2
500
+ df['h_m'] = df['High']-df['m_price'].shift(1)
501
+ df['m_l'] = df['m_price'].shift(1)-df['Low']
502
+
503
+ df['h_m_sum'] = df['h_m'].rolling(window=CR_day).sum()
504
+ df['m_l_sum'] = df['m_l'].rolling(window=CR_day).sum()
505
+ df['cr'] = (df['h_m_sum']/df['m_l_sum'])*100
506
+
507
+ for d in CR_madays:
508
+ df['cr_ma'+str(d)] = talib.MA(df['cr'],timeperiod=d)
509
+
510
+ df.drop(columns = ['m_price','h_m','m_l','h_m_sum','m_l_sum'],inplace=True)
511
+ if not more_details:
512
+ df.drop(columns = ['cr'],inplace=True)
455
513
 
456
514
  #=========== EMV: 简易波动指标
457
515
  """
@@ -467,20 +525,22 @@ def calc_technical(df,start,end, \
467
525
  4)求出EMV的移动平均值EMVA
468
526
  EMVA = EMV的M日移动平均值,M一般设置9日
469
527
  """
470
- df['a'] = (df['High']+df['Low'])/2
471
- df['b'] = (df['High'].shift(1)+df['Low'].shift(1))/2
472
- df['c'] = df['High'] - df['Low']
473
- df['Amount']=df['Close']*df['Volume']
474
- df['em'] = (df['a']-df['b'])*df['c']/df['Amount']
528
+ if technical=='EMV':
475
529
 
476
- df['emv'] = df['em'].rolling(window=EMV_day).sum()
530
+ df['a'] = (df['High']+df['Low'])/2
531
+ df['b'] = (df['High'].shift(1)+df['Low'].shift(1))/2
532
+ df['c'] = df['High'] - df['Low']
533
+ df['Amount']=df[indicator]*df['Volume']
534
+ df['em'] = (df['a']-df['b'])*df['c']/df['Amount']
535
+
536
+ df['emv'] = df['em'].rolling(window=EMV_day).sum()
537
+
538
+ if not isinstance(EMV_madays,list):
539
+ EMV_madays=[EMV_madays]
540
+ for d in EMV_madays:
541
+ df['emv_ma'+str(d)] = talib.MA(df['emv'],timeperiod=d)
477
542
 
478
- if not isinstance(EMV_madays,list):
479
- EMV_madays=[EMV_madays]
480
- for d in EMV_madays:
481
- df['emv_ma'+str(d)] = talib.MA(df['emv'],timeperiod=d)
482
-
483
- df.drop(columns = ['a','b','c','em'],inplace=True)
543
+ df.drop(columns = ['a','b','c','em'],inplace=True)
484
544
 
485
545
  #=========== BOLL: 布林线指标
486
546
  """
@@ -508,24 +568,28 @@ def calc_technical(df,start,end, \
508
568
  这条带状区的宽窄,随着股价波动幅度的大小而变化,股价涨跌幅度加大时,带状区变宽,
509
569
  涨跌幅度狭小盘整时,带状区则变窄。
510
570
  """
511
- df['upper'],df['mid'],df['lower'] = talib.BBANDS(df[indicator], \
512
- timeperiod=BULL_days, \
513
- nbdevup=BULL_nbdevup,nbdevdn=BULL_nbdevdn,matype=BULL_matype)
571
+ if technical=='Bollinger':
572
+
573
+ df['upper'],df['mid'],df['lower'] = talib.BBANDS(df[indicator], \
574
+ timeperiod=BULL_day, \
575
+ nbdevup=BULL_nbdevup,nbdevdn=BULL_nbdevdn,matype=BULL_matype)
514
576
 
515
577
  #=========== TRIX:三重指数平滑移动平均指标
516
578
  """
517
579
 
518
580
  """
519
- df['trix'] = talib.TRIX(df[indicator],timeperiod=TRIX_day)
520
-
521
- if not isinstance(TRIX_madays,list):
522
- TRIX_madays=[TRIX_madays]
523
- for d in TRIX_madays:
524
- df['trix_ma'+str(d)] = talib.MA(df['trix'],timeperiod=d)
581
+ if technical=='TRIX':
525
582
 
526
- if not more_details:
527
- #不保留TRIX
528
- df.drop(columns = ['trix'],inplace=True)
583
+ df['trix'] = talib.TRIX(df[indicator],timeperiod=TRIX_day)
584
+
585
+ if not isinstance(TRIX_madays,list):
586
+ TRIX_madays=[TRIX_madays]
587
+ for d in TRIX_madays:
588
+ df['trix_ma'+str(d)] = talib.MA(df['trix'],timeperiod=d)
589
+
590
+ if not more_details:
591
+ #不保留TRIX
592
+ df.drop(columns = ['trix'],inplace=True)
529
593
 
530
594
  #=========== DMA: 平均线差
531
595
  """
@@ -539,17 +603,19 @@ def calc_technical(df,start,end, \
539
603
  2)求DDD的10日移动平均数值
540
604
  DMA(10) = DDD(10)÷10
541
605
  """
542
- df['ma_shortperiod'] = talib.MA(df[indicator],timeperiod=DMA_fastperiod)
543
- df['ma_longperiod'] = talib.MA(df[indicator],timeperiod=DMA_slowperiod)
544
- df['ddd'] = df['ma_shortperiod'] - df['ma_longperiod']
545
-
546
- if not isinstance(DMA_madays,list):
547
- DMA_madays=[DMA_madays]
548
- for d in DMA_madays:
549
- df['dma'+str(d)] = talib.MA(df['ddd'],timeperiod=d)
550
- #注意:dma1似乎没有意义
606
+ if technical=='DMA':
551
607
 
552
- df.drop(columns = ['ma_shortperiod','ma_longperiod','ddd'],inplace=True)
608
+ df['ma_shortperiod'] = talib.MA(df[indicator],timeperiod=DMA_fastperiod)
609
+ df['ma_longperiod'] = talib.MA(df[indicator],timeperiod=DMA_slowperiod)
610
+ df['ddd'] = df['ma_shortperiod'] - df['ma_longperiod']
611
+
612
+ if not isinstance(DMA_madays,list):
613
+ DMA_madays=[DMA_madays]
614
+ for d in DMA_madays:
615
+ df['dma_ma'+str(d)] = talib.MA(df['ddd'],timeperiod=d)
616
+ #注意:dma1似乎没有意义
617
+
618
+ df.drop(columns = ['ma_shortperiod','ma_longperiod','ddd'],inplace=True)
553
619
 
554
620
  #=========== BIAS: 乖离率
555
621
  """
@@ -560,25 +626,35 @@ def calc_technical(df,start,end, \
560
626
  12日BIAS>+6%是卖出时机;<-5.5%,为买入时机。
561
627
  24日BIAS>+9%是卖出时机;<-8%,为买入时机。
562
628
  """
563
- if not isinstance(BIAS_days,list):
564
- BIAS_days=[BIAS_days]
565
- for d in BIAS_days:
566
- df['ma'] = talib.MA(df[indicator],timeperiod=d)
567
- df['bias'+str(d)] = ((df[indicator]-df['ma'])/df['ma'])*100
629
+ if technical=='BIAS':
568
630
 
569
- df.drop(columns = ['ma'],inplace=True)
631
+ if not isinstance(BIAS_days,list):
632
+ BIAS_days=[BIAS_days]
633
+ for d in BIAS_days:
634
+ df['ma'] = talib.MA(df[indicator],timeperiod=d)
635
+ df['bias'+str(d)] = ((df[indicator]-df['ma'])/df['ma'])*100
636
+
637
+ df.drop(columns = ['ma'],inplace=True)
570
638
 
571
639
  #=========== CCI: 顺势指标
572
640
  """
573
641
  计算过程:
574
642
  CCI(N日) = (TP-MA)÷MD÷0.015
575
643
  说明:TP = (最高价+最低价+收盘价)÷3;MA=最近N日收盘价的累计之和÷N;MD=最近N日(MA-收盘价)的累计之和÷N;0.015为计算系数;N为计算周期,默认为14天
576
- """
577
- if not isinstance(CCI_days,list):
578
- CCI_days=[CCI_days]
579
- for d in CCI_days:
580
- df['cci'+str(d)] = talib.CCI(df['High'],df['Low'],df['Close'],timeperiod=d)
644
+ """
645
+ if technical=='CCI':
646
+
647
+ df['cci'] = talib.CCI(df['High'],df['Low'],df[indicator],timeperiod=CCI_day)
648
+
649
+ if not isinstance(CCI_madays,list):
650
+ CCI_madays=[CCI_madays]
651
+ for d in CCI_madays:
652
+ df['cci_ma'+str(d)] = df['cci'].rolling(window=d).mean()
581
653
 
654
+ #需要显示CCI?
655
+ if not more_details:
656
+ #不保留指标本身
657
+ df.drop(columns = ['cci'],inplace=True)
582
658
  #=========== W%R: 威廉指标
583
659
  """
584
660
  N日W%R = [(Hn-Ct)/(Hn-Ln)]*100
@@ -593,14 +669,16 @@ def calc_technical(df,start,end, \
593
669
  2.高于80,超卖,即将见底,应伺机买进
594
670
  3.与RSI、MTM指标配合使用,效果更好
595
671
  """
596
- if not isinstance(WR_days,list):
597
- WR_days=[WR_days]
598
- for d in WR_days:
599
- df['h_10'] = df['High'].rolling(window=d).max()
600
- df['l_10'] = df['Low'].rolling(window=d).min()
601
- df['wr'+str(d)] = ((df['h_10']-df['Close'])/(df['h_10']-df['l_10']))*100
602
-
603
- df.drop(columns = ['h_10','l_10'],inplace=True)
672
+ if technical=='W%R':
673
+
674
+ if not isinstance(WR_days,list):
675
+ WR_days=[WR_days]
676
+ for d in WR_days:
677
+ df['h_10'] = df['High'].rolling(window=d).max()
678
+ df['l_10'] = df['Low'].rolling(window=d).min()
679
+ df['wr'+str(d)] = ((df['h_10']-df[indicator])/(df['h_10']-df['l_10']))*100
680
+
681
+ df.drop(columns = ['h_10','l_10'],inplace=True)
604
682
 
605
683
  #=========== ROC: 变动速率指标
606
684
  """
@@ -612,39 +690,136 @@ def calc_technical(df,start,end, \
612
690
  ROCMA = ROC的M日数值之和÷M
613
691
  说明:M一般取值为6日
614
692
  """
615
- df['roc'] = talib.ROC(df[indicator],timeperiod=ROC_day)
616
-
617
- if not isinstance(ROC_madays,list):
618
- ROC_madays=[ROC_madays]
619
- for d in ROC_madays:
620
- df['roc_ma'+str(d)] = talib.MA(df['roc'],timeperiod=d)
693
+ if technical=='ROC':
621
694
 
622
- if not more_details:
623
- #不保留roc
624
- df.drop(columns = ['roc'],inplace=True)
695
+ df['roc'] = talib.ROC(df[indicator],timeperiod=ROC_day)
696
+
697
+ if not isinstance(ROC_madays,list):
698
+ ROC_madays=[ROC_madays]
699
+ for d in ROC_madays:
700
+ df['roc_ma'+str(d)] = talib.MA(df['roc'],timeperiod=d)
701
+
702
+ if not more_details:
703
+ #不保留roc
704
+ df.drop(columns = ['roc'],inplace=True)
625
705
 
626
706
  #=========== DMI: 趋向指标
627
707
  """
628
-
708
+ pdi: 正向DI
709
+ mdi: 负向DI
629
710
  """
630
- if not isinstance(DMI_DIdays,list):
631
- DMI_DIdays=[DMI_DIdays]
632
- for d in DMI_DIdays:
633
- df['pdi'+str(d)] = talib.PLUS_DI(df['High'],df['Low'],df['Close'],timeperiod=d)
634
- df['mdi'+str(d)] = talib.MINUS_DI(df['High'],df['Low'],df['Close'],timeperiod=d)
635
-
636
- if not isinstance(DMI_ADXdays,list):
637
- DMI_ADXdays=[DMI_ADXdays]
638
- for d in DMI_ADXdays:
639
- df['adx'+str(d)] = talib.ADX(df['High'],df['Low'],df['Close'],timeperiod=d)
640
- df['adxr'+str(d)] = talib.ADXR(df['High'],df['Low'],df['Close'],timeperiod=d)
641
-
642
- #过滤日期
711
+ if technical=='DMI':
712
+
713
+ if not isinstance(DMI_DIdays,list):
714
+ DMI_DIdays=[DMI_DIdays]
715
+ for d in DMI_DIdays:
716
+ df['pdi'+str(d)] = talib.PLUS_DI(df['High'],df['Low'],df[indicator],timeperiod=d)
717
+ df['mdi'+str(d)] = talib.MINUS_DI(df['High'],df['Low'],df[indicator],timeperiod=d)
718
+
719
+ if not isinstance(DMI_ADXdays,list):
720
+ DMI_ADXdays=[DMI_ADXdays]
721
+ for d in DMI_ADXdays:
722
+ df['adx'+str(d)] = talib.ADX(df['High'],df['Low'],df[indicator],timeperiod=d)
723
+ df['adxr'+str(d)] = talib.ADXR(df['High'],df['Low'],df[indicator],timeperiod=d)
724
+
725
+ #=========== MFI:资金流动指标
726
+ """
727
+
728
+ """
729
+ if technical=='MFI':
730
+
731
+ df['mfi'] = talib.MFI(df['High'],df['Low'],df[indicator],df['Volume'],timeperiod=MFI_day)
732
+ if not isinstance(MFI_madays,list):
733
+ MFI_madays=[MFI_madays]
734
+ for d in MFI_madays:
735
+ df['mfi_ma'+str(d)] = df['mfi'].rolling(window=d).mean()
736
+
737
+ if not more_details:
738
+ #不保留指标本身
739
+ df.drop(columns = ['mfi'],inplace=True)
740
+
741
+ #=========== MOM:动量指标
742
+ """
743
+
744
+ """
745
+ if technical=='MOM':
746
+
747
+ df['mom'] = talib.MOM(df[indicator],timeperiod=MOM_day)
748
+ if not isinstance(MOM_madays,list):
749
+ MOM_madays=[MOM_madays]
750
+ for d in MOM_madays:
751
+ df['mom_ma'+str(d)] = df['mom'].rolling(window=d).mean()
752
+
753
+ if not more_details:
754
+ #不保留指标本身
755
+ df.drop(columns = ['mom'],inplace=True)
756
+
757
+ #=========== BETA:贝塔系数
758
+ """
759
+ 动态贝塔系数?
760
+ """
761
+ if technical=='BETA':
762
+
763
+ df['beta'] = talib.BETA(df['High'],df['Low'],timeperiod=BETA_day)
764
+
765
+ if not isinstance(BETA_madays,list):
766
+ BETA_madays=[BETA_madays]
767
+ for d in BETA_madays:
768
+ df['beta_ma'+str(d)] = df['beta'].rolling(window=d).mean()
769
+
770
+ if not more_details:
771
+ #不保留指标本身
772
+ df.drop(columns = ['beta'],inplace=True)
773
+
774
+ #=========== TSF:时间序列预测
775
+ """
776
+
777
+ """
778
+ if technical=='TSF':
779
+
780
+ df['tsf'] = talib.TSF(df[indicator],timeperiod=TSF_day)
781
+
782
+ if not isinstance(TSF_madays,list):
783
+ TSF_madays=[TSF_madays]
784
+ for d in TSF_madays:
785
+ df['tsf_ma'+str(d)] = df['tsf'].rolling(window=d).mean()
786
+
787
+ if not more_details:
788
+ #不保留指标本身
789
+ df.drop(columns = ['tsf'],inplace=True)
790
+
791
+ #=========== AD:量价指标
792
+ """
793
+
794
+ """
795
+ if technical=='AD':
796
+
797
+ #df['ad'] = talib.AD(df['High'],df['Low'],df[indicator],df['Volume'],timeperiod=AD_day)
798
+ df['ad'] = talib.AD(df['High'],df['Low'],df[indicator],df['Volume'])
799
+
800
+ if not isinstance(AD_madays,list):
801
+ AD_madays=[AD_madays]
802
+ for d in AD_madays:
803
+ df['ad_ma'+str(d)] = df['ad'].rolling(window=d).mean()
804
+
805
+ if not more_details:
806
+ #不保留指标本身
807
+ df.drop(columns = ['ad'],inplace=True)
808
+
809
+
810
+
811
+ #过滤日期===================================================================
643
812
  _,startpd,endpd=check_period(start,end)
644
813
  df1=df[(df.index >= startpd) & (df.index <= endpd)]
645
814
 
815
+ #检查是否加入了计算结果的指标
816
+ dfcols=list(df)
817
+ if len(dfcols) > len(dfcols_original):
818
+ calculated=True
819
+ else:
820
+ calculated=False
646
821
 
647
- return df1
822
+ return df1,calculated
648
823
 
649
824
 
650
825
  #==============================================================================
@@ -2395,52 +2570,42 @@ def security_technical(ticker,start='default',end='default', \
2395
2570
  return df
2396
2571
 
2397
2572
  #==============================================================================
2573
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2398
2574
  if __name__ =="__main__":
2399
2575
  RSI_days=[6,24]
2400
-
2401
- OBV_days=5
2402
-
2403
- MA_days=[5,20]; MACD_fastperiod=12; MACD_slowperiod=26; MACD_signalperiod=9
2404
-
2405
- KDJ_fastk_period=5; KDJ_slowk_period=3; KDJ_slowk_matype=0; KDJ_slowd_period=3
2406
- KDJ_slowd_matype=0
2407
-
2576
+ OBV_days=[5,10]
2577
+ MA_days=[5,20]; EMA_days=[5,20]
2578
+ MACD_fastperiod=12; MACD_slowperiod=26; MACD_signalperiod=9
2579
+ KDJ_fastk_period=5; KDJ_slowk_period=3; KDJ_slowk_matype=0; KDJ_slowd_period=3; KDJ_slowd_matype=0
2408
2580
  VOL_fastperiod=5; VOL_slowperiod=10
2409
-
2410
2581
  PSY_days=12
2411
-
2412
2582
  ARBR_days=26
2413
-
2414
2583
  CR_day=16; CR_madays=[5,10,20]
2415
-
2416
2584
  EMV_day=14; EMV_madays=9
2417
-
2418
- BULL_days=20; BULL_nbdevup=2; BULL_nbdevdn=2; BULL_matype=0
2419
-
2585
+ BULL_day=20; BULL_nbdevup=2; BULL_nbdevdn=2; BULL_matype=0
2420
2586
  TRIX_day=12; TRIX_madays=20
2421
-
2422
2587
  DMA_fastperiod=10; DMA_slowperiod=50; DMA_madays=10
2423
-
2424
2588
  BIAS_days=[6,12,24]
2425
-
2426
- CCI_days=14
2427
-
2589
+ CCI_day=14; CCI_madays=[5,10]
2428
2590
  WR_days=[10,6]
2429
-
2430
2591
  ROC_day=12; ROC_madays=6
2431
-
2432
2592
  DMI_DIdays=14; DMI_ADXdays=6
2593
+ MFI_day=14; MFI_madays=[3,5]
2594
+ MOM_day=10; MOM_madays=[5,20]
2595
+ SAR_day=4; SAR_madays=[5,20]
2596
+ BETA_day=5; BETA_madays=[5,20]
2597
+ TSF_day=14; TSF_madays=[5,10]
2598
+ AD_day=26; AD_madays=[5,20]
2433
2599
 
2434
- ticker='AAPL';ticker_type='auto'
2435
-
2436
- start='2024-3-1'; end='2024-4-12'; ahead_days=30*3
2437
2600
 
2438
- technical='EMV'; indicator='Close'
2601
+ ticker='002594.SZ';ticker_type='auto'
2602
+ start='2024-5-1'; end='2024-6-13'; ahead_days=30*8
2603
+ technical='OBV'; indicator='Close'
2439
2604
 
2440
2605
  attention_values=[0,25,50,75]
2441
- more_details=False
2606
+ more_details=True
2442
2607
  ticker_type='auto'; source='auto'
2443
- ahead_days=30*4
2608
+ ahead_days=30*8
2444
2609
  resample_freq='6H'; smooth=True;linewidth=1.5
2445
2610
  date_range=False; date_freq=False; annotate=False
2446
2611
  graph=['ALL']; printout=False
@@ -2448,70 +2613,111 @@ if __name__ =="__main__":
2448
2613
 
2449
2614
  facecolor=['whitesmoke','papayawhip']
2450
2615
  price_line_style='dotted'; price_line_color='red'; price_line_width=5; price_line_marker='.'
2616
+ marker_sizes=[30,120,250]
2451
2617
 
2452
-
2453
- df=security_technical2(ticker,start,end,technical=technical,marker_sizes=[20,150,300])
2618
+ df=security_technical2(ticker='AAPL',start='2024-5-1',end='2024-6-20', \
2619
+ technical='CR',more_details=True,loc1='upper left',loc2='lower right')
2454
2620
 
2455
2621
  tlist=['RSI','OBV','MACD','KDJ','VOL','PSY','ARBR','CR','EMV','Bollinger', \
2456
2622
  'TRIX','DMA','BIAS','CCI','W%R','ROC','DMI']
2457
2623
  for t in tlist:
2458
2624
  df=security_technical2(ticker,start,end,technical=t,loc1='lower left',loc2='lower right')
2459
2625
 
2460
- def security_technical2(ticker,start='default',end='default', \
2461
- technical=['MACD'],indicator='Close', \
2462
- more_details=False, \
2463
- attention_values=[0,25,50,75,100], \
2464
-
2465
- ticker_type='auto',source='auto', \
2466
-
2467
- #指标的默认参数
2468
- RSI_days=[6,24], \
2469
- OBV_days=5, \
2470
-
2471
- MA_days=[5,20], \
2472
- MACD_fastperiod=12,MACD_slowperiod=26,MACD_signalperiod=9, \
2473
-
2474
- KDJ_fastk_period=9,KDJ_slowk_period=5,KDJ_slowk_matype=1, \
2475
- KDJ_slowd_period=5,KDJ_slowd_matype=1, \
2476
-
2477
- VOL_fastperiod=5,VOL_slowperiod=10, \
2478
- PSY_days=12, \
2479
- ARBR_days=26, \
2480
- CR_day=16,CR_madays=[5,20], \
2481
- EMV_day=14,EMV_madays=9, \
2482
-
2483
- BULL_days=20,BULL_nbdevup=2,BULL_nbdevdn=2,BULL_matype=0, \
2484
-
2485
- DMA_fastperiod=10,DMA_slowperiod=50,DMA_madays=10, \
2486
-
2487
- TRIX_day=12,TRIX_madays=20, \
2488
- BIAS_days=[6,24], \
2489
- CCI_days=14, \
2490
- WR_days=[10,6], \
2491
- ROC_day=12,ROC_madays=6, \
2492
- DMI_DIdays=14,DMI_ADXdays=6, \
2493
-
2494
- #数据提前量
2495
- ahead_days=30*4, \
2626
+ def security_technical2(ticker,start='default',end='default',technical='MACD', \
2496
2627
 
2497
- #绘图参数
2498
- resample_freq='6H',smooth=True,linewidth=1.5, \
2499
- date_range=False,date_freq=False,annotate=False, \
2500
-
2501
- graph=['ALL'],printout=False, \
2502
- loc1='best',loc2='best', \
2503
-
2504
- facecolor=['whitesmoke','papayawhip'], \
2505
- #price_line_style=(0,(1,1)), \
2506
- price_line_style='dotted', \
2507
- price_line_color=['red','green'], \
2508
- price_line_width=1,price_line_marker='o', \
2509
- marker_sizes=[30,120,250], \
2628
+ #不建议使用复权价,因为最高最低价开盘价没有复权价!
2629
+ indicator='Close', \
2630
+
2631
+ #显示指标本身,如果原来未显示的话
2632
+ more_details=False, \
2633
+
2634
+ #显示关注值水平线,每个指标不同,可自定义多个关注值
2635
+ attention_values=[], \
2636
+
2637
+ ticker_type='auto',source='auto', \
2638
+
2639
+ #指标的默认参数
2640
+ RSI_days=[6,14], \
2641
+
2642
+ OBV_days=[5,10], \
2643
+
2644
+ MA_days=[5,20],EMA_days=[5,20], \
2645
+
2646
+ MACD_fastperiod=12,MACD_slowperiod=26,MACD_signalperiod=9, \
2647
+
2648
+ KDJ_fastk_period=9,KDJ_slowk_period=5,KDJ_slowk_matype=1,KDJ_slowd_period=5,KDJ_slowd_matype=1, \
2649
+
2650
+ VOL_fastperiod=5,VOL_slowperiod=10, \
2651
+
2652
+ PSY_days=[6,12], \
2653
+
2654
+ ARBR_days=[26], \
2655
+
2656
+ CR_day=30,CR_madays=[10,20,40,60], \
2657
+
2658
+ EMV_day=14,EMV_madays=[9], \
2659
+
2660
+ BULL_day=20,BULL_nbdevup=2,BULL_nbdevdn=2,BULL_matype=0, \
2661
+
2662
+ DMA_fastperiod=10,DMA_slowperiod=50,DMA_madays=[10], \
2663
+
2664
+ TRIX_day=12,TRIX_madays=[5,10], \
2665
+
2666
+ BIAS_days=[6,12,24], \
2667
+
2668
+ CCI_day=14,CCI_madays=[5,10], \
2669
+
2670
+ WR_days=[13,34,89], \
2671
+
2672
+ ROC_day=12,ROC_madays=[65,12,18], \
2673
+
2674
+ DMI_DIdays=7,DMI_ADXdays=6, \
2675
+
2676
+ #资金流:3日作为信号,5日作为确认信号
2677
+ MFI_day=14,MFI_madays=[3,5], \
2678
+ MOM_day=10,MOM_madays=[5,20], \
2679
+
2680
+ #需要显示SAR
2681
+ SAR_day=4,SAR_madays=[5,20], \
2682
+
2683
+ #需要显示BETA
2684
+ BETA_day=5,BETA_madays=[5,20], \
2685
+
2686
+ #需要显示TSF
2687
+ TSF_day=14,TSF_madays=[5,10], \
2688
+
2689
+ #需要显示AD
2690
+ AD_day=26,AD_madays=[5,20], \
2691
+
2692
+ #数据提前量,用于前置计算指标的移动平均值
2693
+ ahead_days=30*8, \
2694
+
2695
+ #指标线的绘图参数
2696
+ resample_freq='2H',smooth=True,linewidth=1.5, \
2697
+ date_range=False,date_freq=False, \
2698
+
2699
+ #未启用
2700
+ annotate=False, \
2701
+
2702
+ #除了MACD外,其他指标均应为ALL
2703
+ graph=['ALL'], \
2704
+ printout=False, \
2705
+ loc1='best',loc2='best', \
2706
+
2707
+ #图形上下半区的背景颜色
2708
+ facecolor=['whitesmoke','papayawhip'], \
2709
+
2710
+ #价格线的绘图参数
2711
+ #price_line_style=(0,(1,1)), \
2712
+ price_line_style='dotted', \
2713
+ price_line_color=['red','green'], \
2714
+ price_line_width=1,price_line_marker='o', \
2715
+ marker_sizes=[30,120,250], \
2510
2716
  ):
2511
2717
  """
2512
2718
  功能:计算和绘制证券技术分析指标的简易图,仅供进一步探索使用,仅用于单个证券(股债基)
2513
2719
 
2514
- 支持的探索指标:
2720
+ 支持的技术分析指标:
2515
2721
  OBV、SAR、VOL、PSY、ARBR、CR、EMV、TRIX、DMA、BIAS、CCI、W%R、ROC、DMI
2516
2722
  支持的其他指标:不如单独的指令功能强
2517
2723
  MACD、RSI、KDJ、BOLL
@@ -2519,6 +2725,14 @@ def security_technical2(ticker,start='default',end='default', \
2519
2725
  关注的阈值:默认[0,25,50,75,100],attention_values=[0,25,50,75,100], 可以自定义。
2520
2726
  收盘价折线:默认红色虚线,price_line_color='red'
2521
2727
  """
2728
+ # 检查ta-lib是否安装,避免浪费后续的处理
2729
+ try:
2730
+ import talib
2731
+ except:
2732
+ print(" #Error(security_technical2): lack of necessary package, talib")
2733
+ talib_install_method()
2734
+ return None
2735
+
2522
2736
  #检查证券代码
2523
2737
  if not isinstance(ticker,str):
2524
2738
  print(" #Warning(security_technical2): not a security code for",ticker)
@@ -2534,11 +2748,13 @@ def security_technical2(ticker,start='default',end='default', \
2534
2748
 
2535
2749
  #检查指标类别
2536
2750
  tech_list={'Bollinger':'布林带','MACD':'指数平滑异同平均', \
2537
- 'RSI':'相对强弱','KDJ':'随机指标','OBV':'能量潮', \
2538
- 'SAR':'抛物转向','VOL':'成交量','ARBR':'人气与意愿', \
2539
- 'CR':'能力线','EMV':'简易波动','TRIX':'三重指数平滑', \
2540
- 'DMA':'均线差','BIAS':'乖离率','CCI':'顺势线', \
2541
- 'W%R':'威廉比率','ROC':'变动速率','DMI':'趋向线','PSY':'心理线'}
2751
+ 'RSI':'相对强弱','KDJ':'随机指标','OBV':'能量潮', \
2752
+ 'SAR':'抛物转向','VOL':'成交量','ARBR':'人气与意愿', \
2753
+ 'CR':'能力线','EMV':'简易波动','TRIX':'三重指数平滑', \
2754
+ 'DMA':'均线差','BIAS':'乖离率','CCI':'顺势线', \
2755
+ 'W%R':'威廉比率','ROC':'变动速率','DMI':'趋向线','PSY':'心理线', \
2756
+ 'MFI':'资金流','MOM':'动量指标','BETA':'动态贝塔', \
2757
+ 'TSF':'时间序列预测','AD':'量价指标','MA':'移动平均','EMA':'指数移动平均'}
2542
2758
 
2543
2759
  technical1=technical
2544
2760
  if isinstance(technical,list):
@@ -2553,7 +2769,12 @@ def security_technical2(ticker,start='default',end='default', \
2553
2769
 
2554
2770
  #抓取抓取价格数据
2555
2771
  fromdate1=date_adjust(fromdate,adjust=-ahead_days)
2556
- price,found=get_price_1ticker_mixed(ticker=ticker,fromdate=fromdate1, \
2772
+ if 'Adj' in indicator.title():
2773
+ adjust='Adj_only' #最高最低价开盘收盘价均为复权价
2774
+ else:
2775
+ adjust=''
2776
+
2777
+ price,found=get_price_1ticker_mixed(ticker=ticker,fromdate=fromdate1,adjust=adjust, \
2557
2778
  todate=todate,ticker_type=ticker_type,fill=False,source=source)
2558
2779
 
2559
2780
  if found not in ['Found']:
@@ -2566,10 +2787,6 @@ def security_technical2(ticker,start='default',end='default', \
2566
2787
 
2567
2788
  #分位数
2568
2789
  import numpy as np
2569
- """
2570
- max(price['up_down_abs'])
2571
- min(price['up_down_abs'])
2572
- """
2573
2790
  q70=np.percentile(price['up_down_abs'],70)
2574
2791
  q30=np.percentile(price['up_down_abs'],30)
2575
2792
 
@@ -2577,57 +2794,58 @@ def security_technical2(ticker,start='default',end='default', \
2577
2794
  price['marker_size']=price['up_down_abs'].apply(lambda x: big_size if x>=q70 else mid_size if x>=q30 else small_size)
2578
2795
 
2579
2796
  #计算技术指标
2580
- df=calc_technical(price,fromdate,todate, \
2581
- RSI_days=RSI_days, \
2582
- OBV_days=OBV_days, \
2583
-
2584
- MA_days=MA_days, \
2585
- MACD_fastperiod=MACD_fastperiod, \
2586
- MACD_slowperiod=MACD_slowperiod, \
2587
- MACD_signalperiod=MACD_signalperiod, \
2588
-
2589
- KDJ_fastk_period=KDJ_fastk_period, \
2590
- KDJ_slowk_period=KDJ_slowk_period, \
2591
- KDJ_slowk_matype=KDJ_slowk_matype, \
2592
- KDJ_slowd_period=KDJ_slowd_period, \
2593
- KDJ_slowd_matype=KDJ_slowd_matype, \
2594
-
2595
- VOL_fastperiod=VOL_fastperiod, \
2596
- VOL_slowperiod=VOL_slowperiod, \
2597
-
2598
- PSY_days=PSY_days, \
2599
- ARBR_days=ARBR_days, \
2600
- CR_day=CR_day,CR_madays=CR_madays, \
2601
- EMV_day=EMV_day,EMV_madays=EMV_madays, \
2602
-
2603
- BULL_days=BULL_days,BULL_nbdevup=BULL_nbdevup, \
2604
- BULL_nbdevdn=BULL_nbdevdn,BULL_matype=BULL_matype, \
2605
-
2606
- DMA_fastperiod=DMA_fastperiod, \
2607
- DMA_slowperiod=DMA_slowperiod,DMA_madays=DMA_madays, \
2608
-
2609
- TRIX_day=TRIX_day,TRIX_madays=TRIX_madays, \
2610
- BIAS_days=BIAS_days, \
2611
- CCI_days=CCI_days, \
2612
- WR_days=WR_days, \
2613
- ROC_day=ROC_day,ROC_madays=ROC_madays, \
2614
- DMI_DIdays=DMI_DIdays,DMI_ADXdays=DMI_ADXdays, \
2615
-
2616
- indicator=indicator, \
2617
- more_details=more_details)
2618
- #未安装talib
2619
- if df is None:
2620
- return None
2621
-
2622
- if len(df) == 0:
2623
- print(" #Warning(security_technical2): zero records calculated for",technical,"using indicator",indicator)
2624
- return None
2797
+ df,calculated=calc_technical(price,fromdate,todate,technical=technical, \
2798
+
2799
+ RSI_days=RSI_days, \
2800
+ OBV_days=OBV_days, \
2801
+
2802
+ MA_days=MA_days,EMA_days=EMA_days, \
2803
+
2804
+ MACD_fastperiod=MACD_fastperiod,MACD_slowperiod=MACD_slowperiod,MACD_signalperiod=MACD_signalperiod, \
2805
+
2806
+ KDJ_fastk_period=KDJ_fastk_period,KDJ_slowk_period=KDJ_slowk_period, \
2807
+ KDJ_slowk_matype=KDJ_slowk_matype,KDJ_slowd_period=KDJ_slowd_period,KDJ_slowd_matype=KDJ_slowd_matype, \
2808
+
2809
+ VOL_fastperiod=VOL_fastperiod,VOL_slowperiod=VOL_slowperiod, \
2810
+
2811
+ PSY_days=PSY_days, \
2812
+ ARBR_days=ARBR_days, \
2813
+ CR_day=CR_day,CR_madays=CR_madays, \
2814
+ EMV_day=EMV_day,EMV_madays=EMV_madays, \
2815
+
2816
+ BULL_day=BULL_day,BULL_nbdevup=BULL_nbdevup,BULL_nbdevdn=BULL_nbdevdn,BULL_matype=BULL_matype, \
2817
+
2818
+ DMA_fastperiod=DMA_fastperiod,DMA_slowperiod=DMA_slowperiod,DMA_madays=DMA_madays, \
2819
+
2820
+ TRIX_day=TRIX_day,TRIX_madays=TRIX_madays, \
2821
+ BIAS_days=BIAS_days, \
2822
+ CCI_day=CCI_day,CCI_madays=CCI_madays, \
2823
+ WR_days=WR_days, \
2824
+ ROC_day=ROC_day,ROC_madays=ROC_madays, \
2825
+ DMI_DIdays=DMI_DIdays,DMI_ADXdays=DMI_ADXdays, \
2826
+
2827
+ MFI_day=MFI_day,MFI_madays=MFI_madays, \
2828
+ MOM_day=MOM_day,MOM_madays=MOM_madays, \
2829
+
2830
+ #需要显示SAR
2831
+ SAR_day=SAR_day,SAR_madays=SAR_madays, \
2832
+
2833
+ #需要显示BETA
2834
+ BETA_day=BETA_day,BETA_madays=BETA_madays, \
2835
+
2836
+ #需要显示TSF
2837
+ TSF_day=TSF_day,TSF_madays=TSF_madays, \
2838
+
2839
+ #需要显示AD
2840
+ AD_day=AD_day,AD_madays=AD_madays, \
2841
+
2842
+ indicator=indicator, \
2843
+ more_details=more_details)
2625
2844
 
2626
2845
  #技术指标的绘图线
2627
2846
  tech_line_default={'RSI':['rsi'],
2628
2847
  'OBV':['obv'],
2629
2848
  'MACD':['DIF','DEA'],
2630
- #'KDJ':['kdj_k','kdj_d','kdj_j'],
2631
2849
  'KDJ':['kdj'],
2632
2850
  'SAR':['sar'],
2633
2851
  'VOL':['vol'],
@@ -2642,9 +2860,23 @@ def security_technical2(ticker,start='default',end='default', \
2642
2860
  'W%R':['wr'],
2643
2861
  'ROC':['roc'],
2644
2862
  'DMI':['pdi','mdi'],
2645
- 'DMA':['dma'],}
2863
+ 'DMA':['dma'],
2864
+ 'MFI':['mfi'],
2865
+ 'MOM':['mom'],
2866
+ 'BETA':['beta'],
2867
+ 'TSF':['tsf'],
2868
+ 'AD':['ad'],
2869
+ 'MA':['ma'],'EMA':['ema'],
2870
+ }
2871
+
2872
+ #检查计算结果:有问题?
2873
+ if not calculated:
2874
+ print(" #Warning(security_technical2): unsupported technical parameter",technical)
2875
+ print(" Supported technical parameters:")
2876
+ printlist(sorted(list(tech_line_default.keys())),numperline=11,beforehand=' ',separator=' ')
2877
+ return None
2646
2878
 
2647
- #数据后处理
2879
+ #绘图数值缩放比例,以便使指标数量级与股价更加协调
2648
2880
  magnitude_list={'RSI':[1,''],
2649
2881
  'OBV':[1/1000000,'百万'],
2650
2882
  'MACD':[1,''],
@@ -2654,15 +2886,21 @@ def security_technical2(ticker,start='default',end='default', \
2654
2886
  'PSY':[1,''],
2655
2887
  'ARBR':[1,''],
2656
2888
  'CR':[1,''],
2657
- 'EMV':[1,''],
2889
+ 'EMV':[100000000,'亿分之一'],
2658
2890
  'Bollinger':[1,''],
2659
- 'TRIX':[1,''],
2891
+ 'TRIX':[100,'百分之一'],
2660
2892
  'BIAS':[1,''],
2661
2893
  'CCI':[1,''],
2662
2894
  'W%R':[1,''],
2663
2895
  'ROC':[1,''],
2664
2896
  'DMI':[1,''],
2665
2897
  'DMA':[1,''],
2898
+ 'MA':[1,''],'EMA':[1,''],
2899
+ 'MFI':[1,''],
2900
+ 'MOM':[1,''],
2901
+ 'BETA':[1,''],
2902
+ 'TSF':[1,''],
2903
+ 'AD':[1/1000000,'百万'],
2666
2904
  'Volume':[1/1000000,'百万']}
2667
2905
 
2668
2906
  mag_times=magnitude_list[technical1][0]
@@ -2698,27 +2936,21 @@ def security_technical2(ticker,start='default',end='default', \
2698
2936
  df['Volume']=df['Volume'] * magnitude_list['Volume'][0]
2699
2937
 
2700
2938
  #字段排序
2701
- tech_line_collist.sort()
2702
- df1=df[tech_line_collist+[indicator,'Volume','up_down','marker_size']]
2939
+ #tech_line_collist.sort()
2940
+ if 'marker_size' in tech_line_collist:
2941
+ df1=df[tech_line_collist+[indicator,'Volume','up_down']]
2942
+ else:
2943
+ df1=df[tech_line_collist+[indicator,'Volume','up_down','marker_size']]
2703
2944
 
2704
2945
  #绘图----------------------------------------------------------------------
2946
+ print('') #距离上条信息空一行
2947
+
2705
2948
  import matplotlib.pyplot as plt
2706
2949
  import matplotlib.dates as mdates
2707
2950
  #import matplotlib.gridspec as gridspec
2708
- """
2709
- fig = plt.figure()
2710
- ax = fig.add_subplot(111)
2711
- """
2712
- """
2713
- #图ax在上方,ax3在下方
2714
- fig, (ax, ax3) = plt.subplots(2, sharex=True,figsize=(12,9))
2715
2951
 
2716
- #plt.gca().set_facecolor('whitesmoke')
2717
- fig.gca().set_facecolor(facecolor) #放在这里生效,放尾部不生效
2718
- """
2719
2952
  # 创建两行的布局,上半部分高度为4,下半部分高度为1
2720
2953
  fig = plt.figure(figsize=(14,9))
2721
- #fig.gca().set_facecolor(facecolor)
2722
2954
 
2723
2955
  if isinstance(facecolor,str):
2724
2956
  facecolor1=facecolor2=facecolor
@@ -2744,34 +2976,12 @@ def security_technical2(ticker,start='default',end='default', \
2744
2976
  except:
2745
2977
  ax3.set_facecolor('papayawhip')
2746
2978
 
2747
- """
2748
- line0=False; line30=False; line50=False; line80=False
2749
- for l in tech_line_collist:
2750
- lmax=df1[l].max(); lmin=df1[l].min()
2751
- if lmax * lmin < 0: line0=True
2752
- if 100 >= lmax >= 30 and 0 <= lmin <= 30: line30=True
2753
- if 100 >= lmax >= 50 and 0 <= lmin <= 50: line50=True
2754
- if 100 >= lmax >= 80 and 0 <= lmin <= 80: line80=True
2755
-
2756
- ax.plot(df1.index,df1[l],label=l)
2757
-
2758
- #绘制0线
2759
- if line0:
2760
- plt.axhline(y=0,ls=":",c="black",linewidth=2)
2761
- #绘制30线
2762
- if line30:
2763
- plt.axhline(y=30,ls=":",c="green",linewidth=2)
2764
- #绘制50线
2765
- if line50:
2766
- plt.axhline(y=50,ls=":",c="black",linewidth=2)
2767
- #绘制50线
2768
- if line80:
2769
- plt.axhline(y=80,ls=":",c="black",linewidth=2)
2770
- """
2771
2979
  color_list=['k','g','b','c','m','y','r']
2772
2980
  attention_draws=[False] * len(attention_values)
2773
2981
 
2774
2982
  for l in tech_line_collist:
2983
+ if l == 'marker_size': continue
2984
+
2775
2985
  labeltxt=l.upper()
2776
2986
  if labeltxt =='DEA':
2777
2987
  labeltxt='慢线(DEA)'
@@ -2787,7 +2997,7 @@ def security_technical2(ticker,start='default',end='default', \
2787
2997
  pos=attention_values.index(al)
2788
2998
 
2789
2999
  line_al=False
2790
- if lmax >= al >= lmin:
3000
+ if (lmax >= al) and (al >= lmin):
2791
3001
  line_al=True
2792
3002
 
2793
3003
  #如果需要绘制关注线,且尚未绘制过,则绘制
@@ -2800,7 +3010,22 @@ def security_technical2(ticker,start='default',end='default', \
2800
3010
  if mag_label != '':
2801
3011
  ylabeltxt1=ylabeltxt1+'('+mag_label+')'
2802
3012
  ax.set_ylabel(ylabeltxt1,fontsize=ylabel_txt_size)
2803
- ax.legend(loc=loc1,fontsize=legend_txt_size)
3013
+
3014
+ #对图例项目排序
3015
+ # 获取图例句柄和标签
3016
+ handles, labels = ax.get_legend_handles_labels()
3017
+
3018
+ # 指定显示顺序
3019
+ labels_sorted = sort_list_by_len(labels,reverse=False)
3020
+ handles_sorted = []
3021
+ for l in labels_sorted:
3022
+ pos=labels.index(l)
3023
+ h=handles[pos]
3024
+ handles_sorted =handles_sorted +[h]
3025
+
3026
+ # 在指定位置添加新的图例,并按照指定顺序显示
3027
+ ax.legend(handles=handles_sorted,labels=labels_sorted,loc=loc1,fontsize=legend_txt_size)
3028
+ #ax.legend(loc=loc1,fontsize=legend_txt_size)
2804
3029
 
2805
3030
  interval=int(len(df1)/10)+1
2806
3031
  ax.xaxis.set_major_locator(mdates.DayLocator(interval=interval)) # 隔interval天一个标记
@@ -2842,12 +3067,10 @@ def security_technical2(ticker,start='default',end='default', \
2842
3067
  if df1seg['up_down'].values[0] >=0:
2843
3068
  seg_color=price_line_color1
2844
3069
  #labeltxt=ylabeltxt2+'(当日↑)'
2845
- #labeltxt=ylabeltxt2+'(当日≥开盘价)'
2846
3070
  labeltxt=ylabeltxt2+'(当日阳线)'
2847
3071
  else:
2848
3072
  seg_color=price_line_color2
2849
3073
  #labeltxt=ylabeltxt2+'(当日↓)'
2850
- #labeltxt=ylabeltxt2+'(当日<开盘价)'
2851
3074
  labeltxt=ylabeltxt2+'(当日阴线)'
2852
3075
 
2853
3076
  if first_time:
@@ -2856,22 +3079,11 @@ def security_technical2(ticker,start='default',end='default', \
2856
3079
  second_time=False
2857
3080
  else:
2858
3081
  labeltxt=''
2859
- """
2860
- ax2.plot(df1seg.index,df1seg[indicator],label=labeltxt, \
2861
- linestyle=':',color=seg_color,lw=price_line_width,marker=price_line_marker)
2862
- """
3082
+
2863
3083
  ax2.scatter(df1seg.index,df1seg[indicator], \
2864
3084
  s=df1seg['marker_size'], \
2865
3085
  label=labeltxt, \
2866
3086
  linestyle=':',color=seg_color,lw=price_line_width,marker=price_line_marker)
2867
-
2868
-
2869
- """
2870
- ax2.plot(df1.index,df1[indicator],label=ylabeltxt2, \
2871
- linestyle=price_line_style,color=price_line_color1,lw=price_line_width,marker=price_line_marker)
2872
- ax2.scatter(df1down.index,df1down[indicator],label=ylabeltxt2, \
2873
- linestyle=price_line_style,color=price_line_color2,lw=price_line_width,marker=price_line_marker)
2874
- """
2875
3087
 
2876
3088
  ax2.legend(loc=loc2,fontsize=legend_txt_size)
2877
3089
 
@@ -2879,11 +3091,11 @@ def security_technical2(ticker,start='default',end='default', \
2879
3091
  ax3.bar(df1up.index,df1up['Volume'],color=price_line_color1)
2880
3092
  ax3.bar(df1down.index,df1down['Volume'],color=price_line_color2)
2881
3093
 
2882
- ax3.set_ylabel("交易量(百万)",fontsize=ylabel_txt_size -4)
3094
+ ax3.set_ylabel("交易量(百万股)",fontsize=ylabel_txt_size -4)
2883
3095
 
2884
- footnote1="\n注:快线自下而上穿过慢线为金叉,自上而下穿过慢线为死叉。"
2885
- footnote2="价格曲线上端点的大中小对应当日涨跌幅度三分位数的高中低部分。\n"
2886
- footnote3="横轴日期上的空白处为非交易日(周末或公共节假日)。"
3096
+ footnote1="\n注:"
3097
+ footnote2="价格曲线端点大中小对应当日涨跌幅度的高中低情形。"
3098
+ footnote3="横轴日期上的空白处为非交易日。\n"
2887
3099
 
2888
3100
  import datetime; todaydt = str(datetime.date.today())
2889
3101
  footnote4="数据来源:新浪/雅虎/stooq/东方财富等,"+todaydt+"统计"