
    Yajk+                    V   d dl mZ d dlZd dlmZ d dlmZ d dlmZ d dl	Z	d dl
mZ d dlmZmZ d dlmZmZmZmZmZmZ d d	lmZ d d
lmZ d dlmZmZmZmZmZm Z m!Z! d dl"m#Z# d dl$m%Z%  G d d          Z&d Z'ddZ(ddZ)ddZ*ddZ+ddZ,ddZ-ddZ.ddZ/ddZ0ddZ1ddZ2ddZ3dS )     )annotationsN)Decimal)BytesIO)	HTTPError)main)FrankfurterFxProviderTwelveDataFxProvider)MassiveLookupProviderOpenFigiLookupProviderTwelveDataLookupProvider_runtime_secret_value#default_instrument_lookup_providersinstrument_provider_statuses)LookupUnavailable) confirm_instrument_price_mapping)EodhdEquityPriceProviderCompositeEquityPriceProviderFinnhubEquityPriceProviderMassiveEquityPriceProviderTwelveDataEquityPriceProviderequity_price_provider_by_namerefresh_market_prices)connect_memory)apply_migrationsc                  ,    e Zd ZdddZd	 Zd
 ZddZdS )FakeResponseNpayloadobjectheadersdict[str, str] | NonereturnNonec                &    || _         |pi | _        d S N)r   r   )selfr   r   s      *tests/unit/test_provider_integration_v2.py__init__zFakeResponse.__init__$   s    }"    c                    | S r$    r%   s    r&   	__enter__zFakeResponse.__enter__(   s    r(   c                    dS )NFr*   )r%   argss     r&   __exit__zFakeResponse.__exit__+   s    ur(   bytesc                Z    t          j        | j                                      d          S )Nutf-8)jsondumpsr   encoder+   s    r&   readzFakeResponse.read.   s"    z$,''..w777r(   r$   )r   r   r   r    r!   r"   )r!   r0   )__name__
__module____qualname__r'   r,   r/   r6   r*   r(   r&   r   r   #   s_        % % % % %    8 8 8 8 8 8r(   r   c                     t                      } t          |            |                     d           |                     d           |                     d           | S )Nz|INSERT INTO platforms(platform_id,name,platform_type,default_currency,created_at) VALUES('p1','Broker','broker','CHF','now')zINSERT INTO accounts(account_id,platform_id,account_name,account_type,currency,created_at) VALUES('a1','p1','Account','brokerage','CHF','now')zINSERT INTO instruments(instrument_id,asset_class,name,ticker,isin,exchange,currency,created_at) VALUES('usd1','ETF','USD ETF','VTI','US9229087690','NYSE','USD','now'))r   r   execute)conns    r&   
setup_connr=   2   s}    DTLL  P  Q  Q  QLL  b  c  c  cLL  {  |  |  |Kr(   r!   r"   c                   |                      dd           |                     dt          |                     |dz  }|                                 |dz  }|                    dd	           |                    d
           t          d          dk    sJ t          d          dk    sJ t          d          dk    sJ d S )NOPENFIGI_API_KEYF)raisingJARVIS_FINANCE_RUNTIME_DIRsecretsz.envzHTWELVEDATA_API_KEY=td
MASSIVE_API_KEY=mass
JARVIS_OPENFIGI_API_KEY=figi
r2   )encodingi  )TWELVEDATA_API_KEYTWELVE_DATA_API_KEYtd)MASSIVE_API_KEYJARVIS_MASSIVE_API_KEYmass)r?   JARVIS_OPENFIGI_API_KEYfigi)delenvsetenvstrmkdir
write_textchmodr   )monkeypatchtmp_pathrB   env_files       r&   :test_runtime_secret_aliases_include_new_provider_key_namesrU   ;   s    )59993S]]CCC"GMMOOOH~  JQ  R  R  RNN5 !NOOSWWWWW !NOOSYYYYY !PQQU[[[[[[[r(   c                    d }|                      d|           t          dd          }t          j        t          d          5  |                    dd	
           d d d            d S # 1 swxY w Y   d S )Nc                 @    t          dddi t                                )Nz#https://api.openfigi.com/v3/mappingi  Unauthorized)r   r   )r.   kwargss     r&   failz<test_openfigi_401_is_auth_failed_without_crash.<locals>.failJ   s!    =sNTVX_XaXabbbr(   z2jarvis_finance.market_data.catalog.request.urlopen	syntheticr   api_keymin_interval_secondsopenfigi_auth_failed)matchUS9229087690etfqueryasset_class)setattrr   pytestraisesr   search)rR   rZ   providers      r&   .test_openfigi_401_is_auth_failed_without_crashrk   I   s    c c c LdSSS%kPQRRRH	(0F	G	G	G A An%@@@A A A A A A A A A A A A A A A A A As   A++A/2A/c                    t          dd          }|                     |dd            |                    dd          }|sJ |d         j        d	k    sJ |d         j        d
k    sJ d S )Nr[   r   r\   
_post_jsonc                     dddddddgigS )NdataBBG000VTIVanguard Total Stock Market ETFUSUSD)rK   tickernameexchCodecurrencyr*   aks     r&   <lambda>zCtest_openfigi_isin_mapping_mock_returns_candidate.<locals>.<lambda>V   sD    &T\hm  xY  gk  y~  L  L  K@  BA  AB r(   ra   rb   rc   openfigirq   )r   rf   ri   rj   ru   )rR   rj   resultss      r&   1test_openfigi_isin_mapping_mock_returns_candidater   T   s    %kPQRRRH,  1B  1B  C  C  CooNoFFGNN71:*,,,,1:%%%%%%r(   c                   |                      dt          |                     d t                      D             }|g dk    sJ t          d          }d |D             }|d         d                             d	          sJ |d
         d         dk    sJ |d         d         dk    sJ t          j        |          }d|                                vsJ d|                                vsJ d S )NrA   c                    g | ]	}|j         
S r*   rv   .0ps     r&   
<listcomp>zPtest_provider_priority_and_dashboard_status_without_key_leak.<locals>.<listcomp>a   s    GGGAGGGr(   )r}   fmpfinnhub
twelvedatamassiveF)probec                     i | ]}|d          |S Providerr*   )r   rows     r&   
<dictcomp>zPtest_provider_priority_and_dashboard_status_without_key_leak.<locals>.<dictcomp>e   s    333sc*os333r(   EODHDHinweiszEODHD_API_KEY; Low-volumezFrankfurter FXStatusaktivStooqu
   verfügbarapikeyr[   )rM   rN   r   r   
startswithr3   r4   lower)rR   rS   	providersrowslabelsrendereds         r&   <test_provider_priority_and_dashboard_status_without_key_leakr   _   s   3S]]CCCGG!D!F!FGGGIOOOOOOO'e444D33d333F'?9%001LMMMMM"#H-8888'?8$4444z$H8>>++++++hnn........r(   c                   g dfd}|                      d|           ddlm}  |dd                              d	d
          d         }|j        dk    sJ |j        dk    sJ |j        dk    sJ t                    dk    sJ d S )NurlrN   c                n                         |           d|v rddddgiS d|v rddd	d
S d|v rddiS i S )Nz/search?resultrq   rr   )symboldescriptionz/stock/profile2?rt   	NYSE ARCArs   )rx   exchangecountry/quote?cp=
Co@)append)r%   r   rY   callss      r&   fake_get_jsonzJtest_finnhub_lookup_mock_enriches_profile_and_quote.<locals>.fake_get_jsonq   sl    S%@abbcdd$$ %;4PPP= 	r(   zHjarvis_finance.market_data.catalog.FinnhubSymbolLookupProvider._get_jsonr   )FinnhubSymbolLookupProviderr[   r\   rq   rb   rc   r   r   250.12   )r   rN   )rf   "jarvis_finance.market_data.catalogr   ri   rj   r   
last_pricelen)rR   r   r   r   r   s       @r&   3test_finnhub_lookup_mock_enriches_profile_and_quoter   n   s    E      bdqrrrNNNNNN((STUUU\\chv{\||}~F?i''''?k))))((((u::??????r(   c                   |                      dd           |                     dd            t          d                              dd	          d         }|j        d
k    sJ |j        dk    sJ |j        dk    sJ d S )NrD   r[   zEjarvis_finance.market_data.catalog.TwelveDataLookupProvider._get_jsonc                    ddddddddgiS )	Nro   rq   zVanguard Total StockNYSErt   zUnited StatesETF)r   instrument_namer   rx   r   instrument_typer*   r%   r   rY   s      r&   r|   z=test_twelvedata_symbol_lookup_and_key_alias.<locals>.<lambda>   sQ      E  SX  mC  QW  ej  wF  [`  Ha  Ha  Gb  ~c r(   r   )r^   rq   rb   rc   r   rt   )rM   rf   r   ri   rj   ru   trading_currency)rR   r   s     r&   +test_twelvedata_symbol_lookup_and_key_aliasr      s    +[999_  bc  bc  d  d  d%1===DD5^cDddefgF?l****=E!!!!"e++++++r(   c                    ddd}|                      t          d|           t          dd                              dd	
          d         }|j        dk    sJ |j        dk    sJ |j        dk    sJ d S )NpathrN   c                2    |dk    r
ddddddgiS dddd	d
iS )Nz/v3/reference/tickersr~   rq   rr   ARCXr   )ru   rv   primary_exchangetypert   us)ru   currency_namelocaler*   )r%   r   paramss      r&   fake_massive_jsonz=test_massive_reference_lookup_mock.<locals>.fake_massive_json   sS    ***5:[qw  BG  !H  !H   I  J  JeetTTUUr(   _massive_jsonr[   r   r\   rq   rb   rc   r   r   r$   )r   rN   )rf   r
   ri   rj   ru   r   )rR   r   r   s      r&   "test_massive_reference_lookup_mockr      s    V V V V V
 -@QRRR";QOOOVV]bpuVvvwxyF?i''''=E!!!!?f$$$$$$r(   c                   |                      t          dd            |                      t          dd            |                      t          dd            t          d                              d          j        t          d	          k    sJ t          d                              d          j        t          d
          k    sJ t          d                              d          j        t          d          k    sJ t          t          d          t                    sJ t          t          d          t                    sJ d S )N	_json_urlc                    d|v rddinddiS )Nr   r   r   rx   rt   r*   r   s      r&   r|   z9test_equity_price_providers_mock_quotes.<locals>.<lambda>   s1    nw{~n~n~^aci]j]j  FP  RW  EX r(   c                    ddddS )N250.13rt   
2026-05-16)closerx   datetimer*   r   s      r&   r|   z9test_equity_price_providers_mock_quotes.<locals>.<lambda>   s#    jr  AF  T`  aa  aa r(   r   c                    dddigiS )Nr~   r   gGzDo@r*   )r%   r   s     r&   r|   z9test_equity_price_providers_mock_quotes.<locals>.<lambda>   s    YbfikqerdsXt r(   r[   r]   rq   r   r   z250.14r   auto)
rf   r   r   r   	get_pricer   r   
isinstancer   r   rR   s    r&   'test_equity_price_providers_mock_quotesr      sf   2K  BX  BX  Y  Y  Y5{  Ea  Ea  b  b  b2OEtEtuuu%k:::DDUKKQU\]eUfUfffff(===GGNNTX_`hXiXiiiii%k:::DDUKKQU\]eUfUfffff3LAAC`aaaaa3F;;=YZZZZZZZr(   c                    ddl m  G fdd          }  G fdd          }t           |              |            g                              d          }|j        dk    sJ |j        t          d	          k    sJ d S )
Nr   EquityPriceQuotec                  &    e Zd ZdZddd	 fdZdS )
Qtest_composite_equity_price_provider_uses_priority_order.<locals>.MissingProviderr   N
price_dateprovider_symbolrN   r   
str | Nonec               0     |dd | j         dd          S )N missingrestricted_endpoint)r   rx   r   rj   quality_statuserror_messager   r%   r   r   r   s      r&   r   z[test_composite_equity_price_provider_uses_priority_order.<locals>.MissingProvider.get_price   s<    ##ObX\gkgp  BK  [p  q  q  q  qr(   r   rN   r   r   r7   r8   r9   rv   r   r   s   r&   MissingProviderr      sO        NR 	q 	q 	q 	q 	q 	q 	q 	q 	q 	qr(   r   c                  &    e Zd ZdZddd	 fdZdS )
Otest_composite_equity_price_provider_uses_priority_order.<locals>.FreshProviderr   Nr   r   rN   r   r   c               H     |dt          d          | j        d          S )Nrt   250.15freshr   rx   r   rj   r   )r   rv   r   s      r&   r   zYtest_composite_equity_price_provider_uses_priority_order.<locals>.FreshProvider.get_price   sB    ##Oe[bck[l[lw{  xA  RY  Z  Z  Z  Zr(   r   r   r   s   r&   FreshProviderr      sO        NR 	Z 	Z 	Z 	Z 	Z 	Z 	Z 	Z 	Z 	Zr(   r   rq   r   r   )!jarvis_finance.market_data.pricesr   r   r   rj   r   r   )r   r   quoter   s      @r&   8test_composite_equity_price_provider_uses_priority_orderr      s    BBBBBBq q q q q q q q q q
Z Z Z Z Z Z Z Z Z Z
 )//*;*;]]__)MNNXXY^__E>\))));'(++++++++r(   c                   dd t                      D             vsJ t          t          d          t                    sJ t	          j        t                    5  t          g d           d d d            d S # 1 swxY w Y   d S )Neodhdc                    g | ]	}|j         
S r*   r   r   s     r&   r   zJtest_eodhd_is_explicit_low_volume_provider_not_default.<locals>.<listcomp>   s    QQQa16QQQr(   )zupdate-equity-pricesz
--providerr   z	--dry-runz--limit0)r   r   r   r   rg   rh   
SystemExitr   r   s    r&   6test_eodhd_is_explicit_low_volume_provider_not_defaultr      s    QQ+N+P+PQQQQQQQ3G<<>VWWWWW	z	"	" [ [YYYZZZ[ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [s   A99A= A=c            	     >   t                      } t          | dddddd            G fdd	          t          |              d
d          }|j        dk    sJ j        dk    sJ |                     d                                          d         dk    sJ d S )Nusd1r   rq   r   manualztest mapping)instrument_idrj   r   provider_market
confidencenotec                  *    e Zd ZdZdZddd
 fd	ZdS )Htest_refresh_market_prices_uses_explicit_provider_only.<locals>.Providerr   r   Nr   r   rN   r   r   c               j    xj         dz  c_         ddlm}  ||dt          d          dd          S )	N   r   r   rt   r   r   r   r   )r   r   r   r   )r%   r   r   r   r   s       r&   r   zRtest_refresh_market_prices_uses_explicit_provider_only.<locals>.Provider.get_price   sa    NNaNNJJJJJJ##Oe[bck[l[l  xD  U\  ]  ]  ]  ]r(   r   )r7   r8   r9   rv   r   r   r   s   r&   r   r     sT        NR 	] 	] 	] 	] 	] 	] 	] 	] 	] 	]r(   r   rb   r   )rj   re   r   r  zDSELECT provider, close FROM market_prices WHERE instrument_id='usd1'rj   )r=   r   r   updated_countr   r;   fetchone)r<   r   r   s     @r&   6test_refresh_market_prices_uses_explicit_provider_onlyr	     s   <<D$T,hm  @F  S[  bp  q  q  q  q] ] ] ] ] ] ] ] ] ] #4((**%\hiiiF1$$$$>Q<<^__hhjjkuv  {G  G  G  G  G  G  Gr(   c                    g fd}|                      d|           t                                          ddd          t          d          k    sJ dd         v sJ d	d         v r
d
d         v sJ |                      dd            t	          d                              ddd          t          d          k    sJ t	          d                              ddd          t          d          k    sJ d S )Nc                b                         | j                   t          dddddg          S )Nz
2026-05-20rt   CHFg{Gz?)datebaser   rate)r   full_urlr   )reqr.   rY   	seen_urlss      r&   fake_frankfurterzBtest_frankfurter_and_twelvedata_fx_mocks.<locals>.fake_frankfurter   s7    &&&lEE[_``abbbr(   z+jarvis_finance.fx.providers.request.urlopenrt   r  latestz0.89zapi.frankfurter.dev/v2/ratesr   zbase=USDz
quotes=CHFc                 $    t          ddi          S )Nr  0.90)r   ry   s     r&   r|   z:test_frankfurter_and_twelvedata_fx_mocks.<locals>.<lambda>   s    WcekmsdtWuWu r(   r[   r   r  1)rf   r   get_rater   r	   )rR   r  r  s     @r&   (test_frankfurter_and_twelvedata_fx_mocksr     s8   Ic c c c c EGWXXX ""++E5(CCwvVVVV)Yq\99991%%,)A,*F*F*FFEGuGuvvv444==eUHUUY`agYhYhhhhh444==eUHUUY`adYeYeeeeeeer(   )r!   r"   )4
__future__r   r3   decimalr   ior   urllib.errorr   rg   jarvis_finance.cli.mainr   jarvis_finance.fx.providersr   r	   r   r
   r   r   r   r   r   %jarvis_finance.market_data.candidatesr   #jarvis_finance.market_data.mappingsr   r   r   r   r   r   r   r   r   jarvis_finance.storage.databaser   !jarvis_finance.storage.migrationsr   r   r=   rU   rk   r   r   r   r   r   r   r   r   r	  r  r*   r(   r&   <module>r$     s   " " " " " "              " " " " " "  ( ( ( ( ( ( S S S S S S S S                D C C C C C P P P P P P                  ; : : : : : > > > > > >8 8 8 8 8 8 8 8  \ \ \ \A A A A& & & &/ / / /   0, , , ,% % % %	[ 	[ 	[ 	[, , , ,&[ [ [ [G G G G(f f f f f fr(   