Files
profitable-expert-advisor/lab/EAs/__pycache__/quxiuhanidea_alpha_backtest.cpython-312.pyc
T

195 lines
25 KiB
Plaintext
Raw Normal View History

2026-04-24 14:14:09 +02:00
Ë
¼çi=Dãó¨UdZddlmZddlZddlZddlmZddlmZm Z m
Z
m Z ddl Z
ddlZ ddlZdgd¢iZded <eGd
d ««Zdd Zdd
Zd dZd!dZd"dZd#d$dZd%dZd&dZ d' d(dZ d)dZ d* d+dZ d,dZ!d-dZ"d.dZ#d/dZ$d0dZ%d1dZ&e'dk(re&«yy#e$rdZYŒŸwxYw)2aÀ
Quxiuhan Idea - A-share alpha backtest in Python.
Core ideas implemented:
1) Use Fourier-series fitting on rolling windows and pick the order
with maximum "inertia" as structural weight.
2) Use first derivative (slope) at window end as directional weight.
3) Compare candlestick-shape similarity across history and use
forward return of similar windows as pattern signal.
4) Compare multiple time windows and aggregate a stabilized signal.
é)Ú annotationsN)Ú dataclass)ÚDictÚListÚOptionalÚTupleÚ
healthcare)z 300015.SZú 300760.SZz 600276.SHz 600196.SHz 300122.SZz 300347.SZz 603259.SHz 688271.SHzDict[str, List[str]]Ú UNIVERSEScóTeZdZUded<ded<ded<ded<ded<ded<ded <y
) Ú WindowSignalÚintÚwindowÚselected_orderÚfloatÚinertiaÚ
derivativeÚfourier_signalÚsimilarity_signalÚcombinedN)Ú__name__Ú
__module__Ú __qualname__Ú__annotations__©óúCD:/profitable-expert-advisor/lab/EAs/quxiuhanidea_alpha_backtest.pyr
r
+s)à ƒKØÓØ
ƒNØÓØÓØÓØ„Orr
cóˆ|j«j«}|jd«r|jdd«S|S)zO
Convert A-share ticker like 600519.SH / 000001.SZ to yfinance format.
z.SHz.SS)ÚupperÚstripÚendswithÚreplace)Útickers rÚnormalize_ticker_for_yfinancer$6s:ð\‰\^×
#€FØ
Ø~‰~˜e  €Mrc óÀt td«t|«}tj|||dd¬«}|jrt d|d|d«t
|jtj«rQd|jjd«vr|jd d
¬ «}n |jjd«|_|jd d
dddddœ¬«}|gd¢j«j«}dD]}tj||d¬«||<Œ!|j«}tj |j"«|_|S)Nz;yfinance is not installed. Please run: pip install yfinanceF)ÚstartÚendÚ auto_adjustÚprogresszNo data fetched for z (z).ÚOpenréÿÿÿÿé©ÚaxisÚopenÚhighÚlowÚcloseÚ adj_closeÚvolume)r*ÚHighÚLowÚClosez Adj CloseÚVolume©Úcolumns)r/r0r1r2r4Úcoerce)Úerrors)ÚyfÚ ImportErrorr$ÚdownloadÚemptyÚ
ValueErrorÚ
isinstancer:ÚpdÚ
MultiIndexÚget_level_valuesÚ droplevelÚrenameÚdropnaÚcopyÚ
to_numericÚ to_datetimeÚindex)r#r&r'Ú yf_tickerÚdataÚcs rÚ
download_datarP@s=Ü €zÜÐ-¨fÓ5€IÜ
;‰;°3ÀEÐTYÔ Z€DØ ‡z‚zÜШx°r¸)¸ÀBÐ$—,‘,¤§
¡
Ô T—\‘\×2°1Ó —>> "¨1-‰DàŸ<™<×8¸Ó;ˆDŒLà ;‰;àØØØØñ

ð ó €Dð Ò K€DØ
Ü—-‘-  Q¡°ÔˆQŠð ;‰;‹=€DÜ §
¡
Ó+€D„JØ €Krcóœtjdd|«}tj|«|g}td|dz«D]x}|j tj
dtj z|z|z««|j tjdtj z|z|z««Œztj|«S)çð?r,é) ÚnpÚlinspaceÚonesÚrangeÚappendÚcosÚpiÚsinÚ column_stack)ÚorderÚcolsÚks rÚ basis_matrixrcbÜ
˜aÓ €AÜ G‰GA‹J˜ˆ?€DÜ
1e˜a
òØ ”B—F‘F˜1œrŸu™u™9 q™=¨1Ñ ”B—F‘F˜1œrŸu™u™9 q™=¨1Ñ ?‰?˜4Ó Ð rcó†tt|«|«}tjj ||d¬«^}}||z}||fS)N)Úrcond)rcÚlenrUÚlinalgÚlstsq)Úyr_ÚbetaÚy_hats rÚ fit_fourierrnksAÜ”S˜“V˜UÓ#€AÜy‰y˜q !¨4ˆÓ0€H€Dˆ1Ø
‰H€EØ $ˆrcóÔt|«dkrytj|«}|dkry||z
}tddtj|«|z z
«}tj|«}tj
|«dkrd}nOt|«dkDr(t
tj|dd|dd«d «nd}tj|«rd}|dzd
z }t
||z«S) zF
Inertia proxy: explained variance * directional persistence.
érRçê-™—q=rSrTNr+r,)rr,g@) rfrUÚvarÚmaxÚdiffÚstdrÚcorrcoefÚisnan)rirmÚ var_totalÚresidualÚr2ÚslopeÚ persistences rÚ calc_inertiar}rô ˆ1ƒv‚zØäq“ €IØØØ5‰y€HÜ ˆSŸ˜xÓ(¨9Ñ4Ó 5€Bä G‰GEN€EÜ ‡vvˆeƒ}˜ÒØ äILÈUËÐVWÊ”eœBŸK™K¨¨c¨r¨
°E¸!¸"°IÓ>¸EÐ]`ˆ Ü
8‰8 ؈KØ ÑÑ+€KÜ  "rcó@t|«dkDr|dnd}d}td|dz«D]k}||}||dz}dtjz|z}|| |ztj||z«z||ztj
||z«zzz
}|dz
}Œmt
|«S)zK
d/dt of Fourier series at window end. Used as directional weight.
r,rRrT)rfrXrUr[r\rZr) rkr_Út_endrÚidxrbÚb_cosÚb_sinÚws rÚcalc_derivative_signalr„Šô
  ›I¨šMa’¨s€JØ
€CÜ
1e˜a
òˆØS‘ ˆØS˜1‘W‘
ˆØ
‰I˜‰MˆØqb˜5‘j¤2§6¡6¨!¨e©)Ó#4Ñ4°q¸5±yÄ2Ç6Á6È!ÈeÉ)ÓCTÑ7TÑTˆ
Ø ˆq‰ð ô Ó Ðrcóú||z
dz}|dkry|j||dz}tj|d«jd«}tj|d«jd«}tj|d«jd«}tj|d«jd«}tjtj
|dz««} ||z
|dzz }
|tj ||«z
|dzz } tj||«|z
|dzz } tj| |
dd| dd| ddg«}
tjj|
«}|dkry|
|z S) Nr,rr2r+r/r0r1rq) ÚilocrUÚasarrayÚreshapertÚlogÚmaximumÚminimumÚ concatenatergÚnorm)ÚdfÚend_idxrr&Úsegr2Úopen_r0r1ÚretÚbodyÚ up_shadowÚ
low_shadowÚfeatrs rÚcandle_feature_windowr—šs[Ø  ˜qÑ €EØ ˆq‚yØà
'‰'%˜' A™+Ð
&€CÜ J‰Js˜7 $× ,¨RÓ 0€EÜ J‰Js˜6 #× +¨BÓ /€EÜ
:‰:c˜& "× *¨2Ó .€DÜ
*‰*S˜
×
Ó
,€Cä
'‰'”"—&&˜ Ó
(€CØ E‰M˜e e™mÑ ,€DØœŸ
 5¨%Ó0°U¸U±]ÑC€IÜ—**˜U EÓ*¨SÑ0°U¸U±]ÑC€Jä
>‰>˜3  Q R ¨)°A°B¨-¸ÀAÀB¸Ð I€DÜ
9‰9>‰>˜ €DØ ˆuØ $‰;ÐrcóÆttj||«tjj |«tjj |«zdzz «S)Nrq)rrUÚdotrgr)Úbs rÚcosine_similarityrœ±s@Ü ˜˜1“¤§¡§¡°Ó!2´R·Y±Y·^±^ÀAÓ5FÑ!FÈÑ!NÑ Prc
ó,t|||«}|yg}t|dz
||z
«}t|||z
«D]u} t|| |«}
|
Œt||
«} t |j
| d«} t |j
| |zd«}
|
| z
| dzz }|j
| |f«Œw|sy|jdd¬«|d|}tj|Dcgc]\}}td|«Œc}}t¬«}tj|Dcgc]\}}|Œ c}}t¬«}|j«dkrt |j««St tj||«|j«z «Scc}}wcc}}w) NrRr,r2rqcó |dS)Nrr)rjs rú<lambda>z2similarity_forward_return_signal.<locals>.<lambda>Ñs
˜A˜a™D€rT)ÚkeyÚreverse©Údtype)
r—rsrXrr†rYÚsortrUÚarrayÚsumÚmeanr™)rÚpattern_windowÚlookback_windowsÚtop_kÚforward_horizonÚcurrentÚsimsÚ start_idxÚhistÚsimÚc0Úc1ÚfwdÚtopÚsrlÚweightsÚretss rÚ similarity_forward_return_signalrºµsxô$ B¨°Ó@€GØØà&(€DÜN Ð2BÑ(BÓC€Iä
9˜Ñ
 ˆÜ$ R¨¨NÓØ ˆ<Ø Ü ¨ÓÜ
2—77˜1:˜
'ˆÜ
2—7‘7˜1˜ÑÑ
9ˆØB‰w˜2 ™:Ñ&ˆØ S˜#ð ñ Øà‡II‘.¨$€IÔ
ˆvˆ,€CÜh‰h°×¨¨1œ˜C  Ó4¼EÔB€GÜ
8‰8 3×'™4˜1˜a'¬uÔ 5€D؇{{ƒ}˜ÒÜT—Y‘Y“[Ó ˜ Ó¯©«Ñ 7ùó 5ùÛ's ÃF
Ä F
c
ó”g}tj|d«jd«}tj|«j «j
d«j}tj|«jd«j«j«j}t|«} t|«}
tt|««D]?} | |
kr|jdddœ«Œg} |D}
|| |
z
dz| dz}||j!«z
|j«dzz }d}d}d}d}td|dz«D]+}t#||«\}}t%||«}||kDsŒ$|}|}|}|}Œ-||Jt'||«}t)j*|«td|«z}t-|| t|| «|¬ «}d
|zd |zz}| jt/|
||||||¬ ««Œ÷tj0| Dcgc]1}td|j2«d
t5|j6«zzŒ3c}«}tj0| Dcgc]}|j8Œc}t:¬«}|j=«dkrt;|j!««}n0t;tj>||«|j=«z «}t;d
d
d|| zzz «} t)j*|dz«| z}!|j|!|dœ«ŒBtj@||jB¬«}"|"Scc}wcc}w)Nr2r+rRé)ÚsignalÚ
raw_signalr,rqçð¿)rgÍÌÌÌÌÌä?gffffffÖ?)rrrrrrrrSg$@g@)rL)"rUr‡rˆrCÚSeriesÚ
pct_changeÚfillnaÚvaluesÚrollingruÚbfillÚminrsrXrfrYrnr}r„ÚmathÚtanhrºr
rÚabsrrrr™Ú DataFramerL)#rŽÚwindowsÚ max_orderr¨Úout_rowsr2Úret1ÚvolÚmin_wÚmax_wÚwindow_signalsrƒriÚy_normÚ
best_orderÚ best_inertiaÚ best_betaÚ best_yhatr_rmrkrrrrrÚwsr·Ú vol_scaler½Úsig_dfs# rÚ
build_signalsrÜÚsð(*€HÜ J‰Jr˜' #× +¨BÓ /€EÜ
9‰9 × (× Ó 4× ;€DÜ
)‰)D/×
! 
%×
+×
3×
:€Cä ‹L€EÜ ‹L€Eä
”3r“7<FˆØ ˆuŠ9Ø O‰O s¸ à-/ˆàò( ˆa˜!e˜ai ! a¡%Ð(ˆ˜!Ÿ&™&(l q§u¡u£w°¡Ñ7ˆFàˆJ؈L؈I؈Iä˜q )¨a¡-Ó
&Ü)¨&°%Ó8 & v¨uÓ5ؘ)Ø#*LØ!&JØ $IØ %
Ð(¨YÐ-BÐ ¸Fˆ!ŸY™Y 2´¸lÓ5KÑKˆNä @ØØÜ" >°5Ó9Ø /ô !Ð ð˜,¨tÐ6GÑ/GÑGˆHØ × ØØ#-Ø)Ø#1Ø&7Øõ
ð=( ôT—((ÐXfÖgÐRTœC  R§Z¡ZÓ0°C¼#¸b¿m¹mÓ:LÑ4LÓܰÖ@¨2˜2Ÿ;›;ÒÔØ ;‰;‹=˜EÒ ˜vŸ{™{›}Ó-‰JäœrŸv™v g¨vÓ¿¹»ÑGˆJô˜#  t¨c°!©f¡}Ñ!4Ñ6ˆ ܘ:¨Ñ,¨yÑà 6¸ÑEðy<Fô|\‰\˜(¨"¯(©(Ô
3€FØ €MùòhùÚ@s È6M
ÉM
c ó¦|j«}|dj«jd«|d<|d|d<tj|ddkDdtj|ddkdd««|d <|s tj|d d
kDdd«|d <|d j d «jd«|d <|d |d j d «jd«z
j
«|d
<|dz }|d |dz||d
zz
|d<|d|d<d|dzj«|d<d|dzj«|d<|S)Nr2rRrg¸…ëQ¸¾?rS…ëQ¸¾¿r¿Úpositionrr,Úposition_shiftÚturnovergˆÃ@Ú strategy_retÚ
benchmark_retÚ strategy_navÚ
benchmark_nav)rIrUÚwhereÚshiftrÉÚcumprod)Ú signal_dfÚfee_bpsÚ allow_shortrNÚfees rÚ run_backtestrì+s{ð 7‰79€DØw‘-×3°CÓ8€Dˆ˜xÑ(€Dˆ—x‘x  X¡°Ñ 5°s¼B¿H¹HÀTÈ(Á^ÐV[ÑE[Ð]aÐcfÓ<gÓh€DˆÑÙ ÜŸ8™8 D¨Ñ$4°qÑ$8¸#¸CˆˆZÑà! *Ñ3°AÓ=¸cÓB€DÐ ÑØÐÐ6FÑ1G×1MÑ1MÈaÓ1P×1WÑ1WÐX[Ó1\Ñ\×c€DˆÑà

€CØÐ 0Ñ1°D¸±KÑ?À#ÈÈZÑHXÑBXÑX€DˆÑØ  ™K€DˆÑà $ ~Ñ"6Ñ6×A€DˆÑØ  4¨Ñ#8ÑC€DˆÑØ €Krc
ó¢|d}|d}t|«}td|dz «}t|jddz
«}t|jdd|z zdz
«}t|j «t j d«z«}||dzz }|j«} || z dz
}
t|
j««} t|d d
kDj««} t|d
kDj«td |d
k7j««z «}
t|d jddz
«}||z
}||||| |
| ||d
œ S)Nrág•Ö&è .>g€o@r+rSéürqrr,) Ú total_returnÚ
annual_returnÚ
annual_volÚsharpeÚ max_drawdownÚwin_rateÚ
trade_daysÚbenchmark_total_returnÚ
excess_return) rfrsrr†rurUÚsqrtÚcummaxrÆr)ÚbtÚdailyÚnavr^ÚyearsrïÚdrawdownÚmax_ddÚtradesrôÚ bench_totalÚexcesss rÚ calc_metricsrDsUØ ˆ €EØ
ˆ
€CÜ ˆB‹€AÜ a˜%‘iÓ €E䘟 "™¨Ñ,€Lܘ#Ÿ(™( 2™,¨3°©;Ñ7¸>€MÜu—yy“{¤R§W¡W¨S£\Ñ2€JØ