
    pj-                        d Z ddlmZ ddlmZmZ ddlZddlZ	ddl
ZddlmZ ed   Z	 ddlmZ dd	d
ddZ	 	 	 	 	 	 	 	 ddZddZ	 	 	 	 	 	 	 	 	 	 	 	 ddZddZdddd	 	 	 	 	 	 	 	 	 ddZddZy# e$ r dZY Lw xY w)u   
Chan Johansen triplet mean-reversion (Ex 2.7–2.8).

Unit portfolio from first Johansen eigenvector on log prices; linear z-score
``numUnits = -(yport - MA) / STD`` with half-life lookback; dollar-position PnL.
    )annotations)AnyLiteralN)rolling_zscore)bookcausal)coint_johansen   x   )defaultcapc                   t        j                  |       }t        j                  |      r-d|cxk  r|k  r"n |S t	        dt        t        |                  S |S )N      )uscalculate_half_lifenpisfinitemaxintround)spreadr   r   hls       H/opt/rentech/trading_bot/RenTech/strategy_stack/chan_johansen_triplet.pyhalf_life_lookbackr      sH    				'B	{{21>c>N 1c%)n%%N    c                `   |j                  t        j                        }|j                  | j                        j                  t        j                        }| j                  t        j                        }|j                  |d      j                  |d      }|j                         }|j                  d      |z  j                  d      }|j                  d      j                         j                  d      j                  dt        j                        }	||	z  j                  d      S )zEx 2.8 dollar-position return.r   axisr           )astyper   float64reindexindexmul
pct_changeshiftsumabsreplacenanfillna)
pricesunit_weights	num_unitsnuwpx
dollar_pospctpnlgrosss
             r   chan_dollar_portfolio_returnsr7   "   s     
		"**	%BV\\*11"**=A	rzz	"Br"&&r&2J
--/CA$
)
)q
)
1CQ##%))q)199#rvvFE%K$$r   c               `   | j                  |t        d|dz              j                         }| j                  |t        d|dz              j                  d      }| |z
  |j	                  dt
        j                        z  }| }|dk(  r|j                  dd      }|j                  d      S )	N   )min_periodsr   )ddofr    r   g      g      @)	rollingr   meanstdr*   r   r+   clipr,   )r   lookbackfidelitymusigzunitss          r   linear_zscore_unitsrF   2   s    	c!X].C	D	I	I	KB
..s1h!m/D.
E
I
Iq
I
QC	"C00ABE8

4%<<r   c                  t         t        d      |dk(  r| j                  d |dz    }n5||z
  |z  dk7  r||k7  ry t        d||z
  dz         }| j                  ||dz    }t	        |      |k  ry t        |j                         dd      }|j                  d d df   j                  t        j                        }|d   dk7  r||d   z  }|S )Nz'statsmodels required for Johansen testsr   r   r   	det_order	k_ar_diff)
r	   ImportErrorilocr   lento_numpyevecr!   r   r"   )	log_pxtrA   	min_train
refit_barswindowstartresevs	            r   johansen_eigenvector_atrX   <   s     CDD6Wq1u%	MZ'1,iAq9}q()UQU+
6{Y
*a1
EC	!Q$		rzz	*B	!uz"Q%ZIr   c                   t         t        d      | j                  d      j                  t        j
                        }t        |      dk  rt        d      t        t	        j                  |      j                         dd	      }t        |j                  d         }t        |j                  d
         }|j                  dddf   j                  t        j
                        }|d   dk7  r||d   z  }|||fS )z
    Johansen trace test for r=0. Returns (trace_stat, crit_95, eigenvector).

    ``crit_95`` is the 95% critical value for rejecting r=0.
    Nzstatsmodels requiredanyhow<   zneed >= 60 rows for Johansenr   r   rH   )r   r   )r	   rK   dropnar!   r   r"   rM   
ValueErrorlogrN   floatlr1cvtrO   )rP   arrrV   tracecrit95rW   s         r   johansen_trace_pvaluerg   V   s     011
--E-
"
)
)"**
5C
3x"}788
--/1
JC#''!*E3774=!F	!Q$		rzz	*B	!uz"Q%Z&"r   r   ?      )rA   rS   rR   c               n   | j                  d      j                  t        j                        }t	        |j
                        }t        j                  |      }t        |      }t        j                  |t        |      ft        j                        }d}	t        ||      D ]  }
t        ||
|||      }||}	|	|	||
<     t        j                  ||j                  |      j                         }||z  j!                  d      }t#        |      }t%        |||      }t'        |||      }|||||d	fS )
z/Backtest one fixed triplet (columns = tickers).rZ   r[   N)rA   rR   rS   )r$   columnsr   r   )rA   )r@   rR   rA   legs)r^   r!   r   r"   listrk   r`   rM   fullr+   rangerX   pd	DataFramer$   ffillr(   r   rF   r7   )r-   rA   rS   rR   r2   colsrP   nrO   last_evirW   evec_dfyportlbrE   rets                    r   johansen_linear_tripletr{   j   s!    
5	!	(	(	4B

DVVBZFBA77As4y>266*D!%G9a  $AI*
 >GDG ll4rxx>DDFG'\A&E	E	"BrH=E
'GU
;CRiXW[\\\r   c                   | j                  d      j                  t        j                        }t	        j
                  ||j                        }||z  j                  d      }t        t        j                  |            S )NrZ   r[   )r$   r   r   )r^   r!   r   r"   rp   Seriesrk   r(   ra   r   r   )r-   rO   r2   r1   rx   s        r   unit_portfolio_half_lifer~      s_    	5	!	(	(	4B
		$bjj)A!VLLaL E''.//r   )r   	pd.Seriesr   r   r   r   returnr   )r-   pd.DataFramer.   r   r/   r   r   r   )r   r   r@   r   rA   Fidelityr   r   )rP   r   rQ   r   rA   r   rR   r   rS   r   r   znp.ndarray | None)rP   r   r   ztuple[float, float, np.ndarray])
r-   r   rA   r   rS   r   rR   r   r   z tuple[pd.Series, dict[str, Any]])r-   r   rO   z
np.ndarrayr   ra   )__doc__
__future__r   typingr   r   numpyr   pandasrp   universe_scannerr   %RenTech.strategy_stack.statarb_enginer   r   statsmodels.tsa.vector_ar.vecmr	   rK   r   r7   rF   rX   rg   r{   r~    r   r   <module>r      s   #     @#$=
 =?3 %%% % 	% 
 	
   4. "]] ] 	]
 ] &]<0c  Ns   A2 2A<;A<