
    oh{              	          d dl mZ d dlmZ d dlZd dlZej                  j                  ej                  j                  ej                  j                  ej                  j                  e      d                   d dlmZ d dlmZ d dl d dlmZ d d	lmZmZmZmZ d
 Zd Zd Zd Zd Zd Zd Zd Zd Z d Z!d Z"d Z#d Z$d Z%d Z&d Z'd Z(d Z)d Z*d Z+d Z,d Z-d eee.ef      fd!Z/d" Z0y)#    )defaultdict)ClientNz..)CoingeckoAPI)JupAPI)*)clickhouse_manager)OptionalDictListAnyc                 ,    t        j                  |       S )N)r   get_wallet_transactions)wallets    ;/home/ubuntu/SOL_API/sol_API/src/v3/utils/wallet_analyze.pyget_wallet_transactions_from_DBr      s    55f==    c                     | st        d       y	 t        j                  |       }|rt        dt        |        d       |S # t        $ r}t        d|        Y d }~yd }~ww xY w)Nu?   ⚠️  Нет транзакций для сохраненияFu   ✅ Сохранено u.    транзакций в базу данныхuC   ❌ Ошибка при сохранении транзакций: )printr   insert_transactionslen	Exception)transactionsresultes      r   add_transactions_to_DBr      sl    OP#77E+C,=+>>lmn STUSVWXs   0A 	A"
AA"c                 2   | sg S t        dd      }g }	 | D ]W  }d}|j                  |d|i      }|r(|d   }|j                  |d   |d   |d   xs dd	       C|j                  |d dd	       Y 	 |j                          |S # |j                          w xY w)
N	localhosttokens_info)databasez
                SELECT token_address, creator, migrated
                FROM tokens
                WHERE token_address = %(token)s
            tokenr         r    creatormigtime)r   executeappend
disconnect)tokensclientr   r    queryrowsrows          r   -get_tokens_migration_time_and_creator_from_DBr.   #   s    	K-8FF 	EE >>%'5)9:D1g V"1v"1v{  "#  #	. 	M 	s   AB Bc                 H    t        j                  |       }|d   }|d   }||fS )Nmigration_startedcreator_hash)r   get_token_pool_info)r    	pool_infomigration_timer$   s       r   -get_token_migration_time_and_creator_from_JUPr5   F   s2    **51I23N'G7""r   c                    t        |       }|D ci c]  }|d   |
 }}g }| D ]  }|j                  |      }||d   |d   dk(  rlt        |      \  }}|rG||r|nd}|j                  |||d       Q|r||d<   ||d<   n
||d<   d|d<   |j                  |       z|s}|j                  |       |j                  |        |S c c}w )Nr    r$   r%   r   r!   r#   )r.   getr5   r'   )	r)   
token_dataentrytoken_data_dictr   r    r4   r$   new_migtimes	            r   %get_tokens_migration_time_and_creatorr<   L   s    >vFJ:DEuW~u,EOEF !##E*=E),4i8HA8M&STY&Z#NG=4B.KMMEgR]"^_%+2i(+9i(+2i(+,i(MM%(MM%(MM% -!0 M7 Fs   Cc                     t               j                  | d      }t        |d       }t        |d         t        |d         d}|S )N1_DAY)intervalc                     | d   S )Nhigh )cs    r   <lambda>z+get_ath_of_token_with_JUP.<locals>.<lambda>m   s
    &	 r   keyrA   time)	ath_priceath_time)r   get_all_candlesmaxint)r    all_candles
ath_candleath_infos       r   get_ath_of_token_with_JUPrP   k   sP    (**57*CK[&9:J F+,F+,H Or   c                     | j                  dd      }| j                  dd      }| j                  d      }|dk(  ryt        j                  |      }t        ||z        |z  dz  }|S )N	delta_solr   delta_tokenr!   	blocktimei ʚ;)r7   r   get_sol_price_on_timestampabs)transactionrR   rS   	timestamp	sol_pricemcs         r   get_market_capr[   y   si    Q/I//-3K,Ia77	BI	Y$	%		1M	ABIr   c                 R   g }t        | d       D ]  }|j                  dd      }|j                  dd      }|j                  d      dk(  r6|dkD  r1|}|dk7  rt        |      |z  nd}|j                  ||d       d |d	<   r|j                  d      d
k(  s|dk  st        |      }d}|dkD  rT|rR|d   }	t	        ||	d         }
||
|	d   z  z  }|	dxx   |
z  cc<   ||
z  }|	d   dk(  r|j                  d       |dkD  r|rRt        |      }|dk7  r||z
  |z  dz  nd |d	<    | S )Nc                 &    | j                  dd      S NrT   r   r7   xs    r   rD   z4get_profit_percent_to_transactions.<locals>.<lambda>   s    {A1F r   rE   rS   r   rR   typebuy)amountpriceprofitsell        rd   re   d   )sortedr7   rV   r'   minpop)r   
fifo_queuetxrS   rR   rd   re   sold_amount
total_costlotused_amountrevenues               r   "get_profit_percent_to_transactionsrt      sW   J\'FG bff]A.FF;*	66&>U"{Q F/5{C	NV+E%@ABxLVVF^v%+/k*KJ/j m!+s8}=kCL88
H,{*x=A%NN1% /j )nGHRVWGj0J>D]aBxL+b, r   c                 &    t        d | D              S )Nc              3      K   | ]B  }|j                  d       dk(  xr( t        |j                  dd      cxk  xr	 t        k  nc  D yw)rb   rc   MCr   Nr7   MIN_MARKET_CAPMAX_MARKET_CAP).0rn   s     r   	<genexpr>z-get_token_buys_in_valid_mc.<locals>.<genexpr>   sA       	v%WNbffT1o$W$WWs   AA
)any)r   s    r   get_token_buys_in_valid_mcr~      s       r   c                    | r| j                  d      syd}| j                  dg       D ]Z  }|j                  dg       D ]C  }|j                  d      dk(  st        |j                  dd      cxk  r
t        k  s<n ?|dz  }E \ |S )uf  
    Считает общее количество покупок в валидном MC по всем токенам кошелька
    
    Args:
        wallet_result: результат анализа кошелька с транзакциями
    
    Returns:
        int: общее количество покупок в валидном MC
    r)   r   r   rb   rc   rw   r!   rx   )wallet_result
total_buystoken_entryrn   s       r   count_all_buys_in_valid_mcr      s      1 1( ;J$((26  //."5 	 Bv%'"&&q/C^Ca
	   r   c                 d   t        | d       } d}d}d}| D ]  }|j                  d      dk(  r)||j                  d      }||j                  dd      z  }@|j                  d      d	k(  sU|t        |j                  dd            z  }|dk  sy|||j                  d      } n |y|y
||z
  S )uQ  
    Рассчитывает время удержания токена от первой покупки до первой полной распродажи (обнуления баланса).
    Игнорирует все транзакции после первой полной распродажи.
    Логика идентична mig_db.py

    Возвращает:
        int: время удержания в секундах
        'hold': если продаж не было и баланс не обнулился  
        None: если покупок не было
    c                 &    | j                  dd      S r^   r_   r`   s    r   rD   z%get_first_hold_time.<locals>.<lambda>   s    aeeK6K r   rE   r   Nrb   rc   rT   rS   rg   hold)rj   r7   rV   )r   balancefirst_buy_timefirst_full_sell_timern   s        r   get_first_hold_timer      s     ,,KLLGN 	66&>U"%!#!4rvvmQ//GVVF^v%s266-344G!| :')vvk':$	 #.00r   c                    | r|sy|D ci c]  }|d   |
 }}d}d}| j                  dg       D ]  }|j                  d      s|d   }|j                  |i       j                  dd      }|dk  rBd}	d}
t        |d	   d
       D ]R  }|d   |kD  r nH|d   dk(  r$t        |d   cxk  r	t        k  rn n|	|d   z  }	d}
9|d   dk(  sB|	t	        |d         z  }	T |
s|dz  }|	dkD  s|dz  } |dkD  r||z  dz  S dS c c}w )Nrh   r    r   r)   buy_in_valid_mcr%   r!   Fr   c                     | d   S )NrT   rB   r`   s    r   rD   z2get_tokens_hold_befor_migrations.<locals>.<lambda>   s
    AkN r   rE   rT   rb   rc   rw   rS   Trg   ri   )r7   rj   ry   rz   rV   )r   r   itemtokens_info_dictheld_before_migrationbought_before_migrationr   r    r4   r   has_valid_buyrn   s               r    get_tokens_hold_befor_migrationsr      se   8CDWt+DD$((26 +01G$)--eR8<<YJQ^4:RS 	2B+/&zU"~D'S^'S2m,, $Fv%3r-011	2 #q(#{%*%5+8 G^`aFa!$;;sBjgjjA Es   C?c                    t        |       }|s| g dS |d   j                  d      } t        t              }|D ]8  }t	        |t
              s|j                  d      }||   j                  |       : g }|j                         D ]5  \  }}|}t        |      }	t        |      }
||	|
|d}|j                  |       7 | |d}|S )N)r   r)   r   r   mint_address)r    r   first_hold_timer   )
r   r7   r   list
isinstancedictr'   itemsr~   r   )r   wallet_transactions_resulttoken_groupsrn   	token_keyanalyzed_tokensr    r   analyzed_transactionsr   r   token_resultr   s                r   "process_wallet_transactions_resultr     s    !@!H% B//'*..x8F t$L( /b$~.I#**2./
 O  ,113 -| ,45JK-.CD ..1	
 	|,-" !F
 Mr   c                 B   | r| j                  d      sy| j                  dg       }g }|D ]  }|j                  d      s|j                  dg       }|s*|D cg c]  }|j                  d      dk(  s| }}|sQt        |d       }|j                  d	d      }|st|j                  |        |sy|j                          d}	t	        |      }
d}t        |
      D ]8  }||   ||   z
  d
k\  r|dz  }||   ||   z
  d
k\  r||z
  dz   }t        |	|      }	: |	S c c}w )Nr)   r   r   r   rb   rc   c                 &    | j                  dd      S r^   r_   r`   s    r   rD   z)get_max_tokens_per_hour.<locals>.<lambda>G  s    k18M r   rE   rT   i  r!   )r7   rk   r'   sortr   rangerK   )r   r   purchase_timesr   r   rn   buy_transactions	first_buy
block_time	max_countnleftrightcounts                 r   get_max_tokens_per_hourr   5  sU    1 1( ;#''"5ON& .01"~r:)5Q259PBQQ(.MN	]];2
!!*-.  INADq *U#nT&::dBAID U#nT&::dBq 	5)		* / Rs   D3Dc                 B   | r| j                  d      sy| j                  dg       }d}d}|D ]^  }|j                  d      s|j                  d      }|dz  }t        |t        t        f      r|t        k  sK|dk7  sQ|dz  }W|Z|dz  }` |dk(  ry||z  dz  }d|z
  S )	u  
    Рассчитывает процент токенов с достаточным временем удержания.
    Логика аналогична filters.py: токен валиден если hold_time >= MIN_HOLD_TIME_SECONDS
    или если это большое значение (2^63-1, означающее что токены все еще держатся).
    r)   g      Y@r   r   r   r!   l    ri   )r7   r   rL   floatMIN_HOLD_TIME_SECONDS)r   r   tokens_with_short_holdtotal_tokensr   r   short_hold_percents          r   get_hold_time_on_wallet_percentr   \  s      1 1( ;#''"5OL& (01%//*;< oU|4!66?{;[&!+&$"a'"(" q 1<?3F%%%r   c                    | r| j                  d      sy| j                  dg       }d}d}|D ]  }|j                  d      s|j                  dg       D ]n  }|j                  d      dk7  r|j                  dd      }t        |cxk  r	t        k  sn @t        |j                  d	d            }|d
z  }|t        k\  sj|d
z  }p  |dk(  ry||z  dz  }|S )Nr)   rh   r   r   r   rb   rc   rw   rR   r!   ri   )r7   ry   rz   rV   MIN_BUY)	r   r   r   big_buysr   rn   rZ   rR   big_buys_percents	            r   get_min_buy_percentr     s     1 1( ;#''"5OJH& 01//."5 	Bvvf~& aB"b:N:BFF;23I!OJG#A		$ Q :-4r   c                    | r| j                  d      sy| j                  dg       }|D ci c]  }|d   |
 }}d}d}|D ]  }|j                  d      s|dz  }|j                  d      }|j                  |i       }	|	j                  dd      sRdkD  sX|j                  dg       }
t        fd	|
D              }|s|dz  } |dk(  ry||z  d
z  }|S c c}w )Nr)   rh   r    r   r   r!   r%   r   c              3   t   K   | ]/  }|j                  d       dk(  xr |j                  dd      k   1 yw)rb   rc   rT   r   Nr_   )r{   rn   r4   s     r   r|   z(get_migration_percent.<locals>.<genexpr>  s>      & v%'TBFF;,Bn,TT&s   58ri   )r7   r}   )r   r   r   r   r   migration_tokensr   r   r    
token_infor   buy_until_migrationmigration_percentr4   s                @r   get_migration_percentr     s    1 1( ;#''"5O8CDWt+DDL& &01(%))%4
#	15nq0&??>2>L"% &&& # # A% !&$ q)L8C?7 Es   Cc                    | r| j                  d      sy| j                  dg       }| j                  d      }|sy|D ci c]  }|d   |
 }}d}d}|D ]X  }|j                  d      s|dz  }|j                  d      }	|j                  |	i       }
|
j                  d      }||k(  sT|dz  }Z |dk(  ry||z  d	z  }|S c c}w )
Nr)   rh   r   r    r   r   r!   r$   ri   r_   )r   r   r   r   r   r   created_tokensr   r   r    r   r$   created_percents                r   get_created_tokens_percentr     s     1 1( ;#''"5Ox(F8CDWt+DDNL& 
 01(%))%4
..+faN
  q%4;O+ Es   B?c           	         t         }t        }| r| j                  d      sy| j                  dg       }|D ci c]  }|d   |
 }}d}d}|D ]_  }	|	j                  d      s|	j                  d      }
|j                  |
i       }|j                  dd      }|dv r|dz  }	 t        |
      }|d	   |d
   }|	j                  dg       D cg c]c  }|j                  d      dk(  rM|j                  dd      |k  r8t        |j                  dd      cxk  r	t
        k  rn n|j                  dd      e }}|rt        fd|D              |k\  r|dz  }|dkD  s|	j                  dg       D cg c]S  }|j                  d      dk(  r=|j                  dd      |k  r(t        |j                  dd      cxk  r	t
        k  rn n|U }}|	j                  dg       D cg c]S  }|j                  d      dk(  r=|j                  dd      |kD  r(t        |j                  dd      cxk  r	t
        k  rn n|U }}|r|s|dz  }	 t        |
      }|d	   |d
   }|D cg c])  }|j                  dd      |k  r|j                  dd      + }}|rt        fd|D              |k\  r|dz  }b |dk(  ry||z  dz  }||k\  S c c}w c c}w #  Y xY wc c}w c c}w c c}w #  Y xY w)Nr)   Fr    r   r   r%   )r   r!   r!   rH   rI   r   rb   rc   rT   rw   c              3   4   K   | ]  }|z
  |z  d z    ywri   NrB   r{   rZ   rH   s     r   r|   z%filter_normal_plus.<locals>.<genexpr>  s     %Wby2~&;c&A%W   c              3   4   K   | ]  }|z
  |z  d z    ywr   rB   r   s     r   r|   z%filter_normal_plus.<locals>.<genexpr>4  s     )["9r>R*?#*E)[r   ri   )ADMISSION_PERCENTPROFIT_PERCENT_FOR_NORMALSr7   rP   ry   rz   rK   )r   r   admission_percentprofit_percentager   r   r   valid_tokens_countprofitable_tokens_countr   r    r   r4   rO   rI   rn   
valid_buyspre_migration_buyspost_migration_buysprofit_percentrH   s                       @r   filter_normal_plusr     s=   '0 1 1( ;#''"5O8CDWt+DD& D01(%))%4
#	15 V#!#4U;$[1	#J/ /:oonb.Q(*v%/{A.(:&"&&q/K^K FF4O
  #%WJ%W"W[l"l+q0+ a )__^R@"FF6Ne+FF;*n<"bffT1oGG " " )__^R@#FF6Ne+FF;*^;"bffT1oGG # # &*="a'"8?H ( 5I'
3H 3F",.66+q1X= tQ"J "
 "c)[PZ)[&[_p&p/14/CDL Q-0BBcIN..._ E.
"#""sP   K")KA(K3 K0AKAKK$.K K$KKK$$K)c	                     	 |r)|r'|r%|r|r| dk(  ry|dk\  ry|dk(  ryyt        ||      ryyy# t        $ r}	t        d	|	        Y d }	~	y
d }	~	ww xY w)Nr!   z
GOLD FRESHr"   GOLDSILVER
NORMALPLUSNORMALTRASHzERROR in classification: ERROR)r   r   r   )

len_tokenslen_tokens_with_buy_in_valid_mcis_tokens_per_hour_validis_hold_time_validis_min_buy_validis_migration_validis_created_tokens_validr   r   r   s
             r   classificationr   @  sw     ":?O!&=?'6!;%8A='  &m[A'  )!-.s    . . . . 	AA

Ac                 D   |st        d       yt        t              }|D ]N  }t        |t              s|j                  d      xs |j                  d      }|s;||   j                  |       P g }|j                         D ]U  \  }}g }t        |d       }	|	D ]  }|j                  dd      }
|j                  d	d      }|j                  d
      }t        |      }|j                  d      |d|j                  d      ||
|j                  d      |d}|j                  |        t        |      }|D ]  }| ||j                  dd      |j                  d
d      |j                  d      |j                  dd      |j                  d	d      |j                  dd      |j                  dd      |j                  dd      d
}|j                  |        X |r8t        |      }|rt        d|  dt        |       d       yt        d|         yt        d       y)u  
    Принимает сырые транзакции кошелька, анализирует их и сохраняет в базу данных.
    
    Args:
        wallet_address: адрес кошелька
        raw_transactions: список транзакций для анализа
    
    Returns:
        bool: True если анализ и сохранение успешны, False иначе
    u9   ⚠️  Нет транзакций для анализаFr   token_extractedc                 &    | j                  dd      S r^   r_   r`   s    r   rD   z-analyze_wallet_transactions.<locals>.<lambda>|  s    {TUAV r   rE   rS   r   rR   rb   	signatureNrT   fee)r   rb   rf   rT   rR   rS   r   rw    rf   rw   )
wallet_addressr   r   rb   rf   rT   rR   rS   r   rw   u"   ✅ Анализ кошелька u(    завершен, обработано u    токеновTuZ   ❌ Ошибка при сохранении данных анализа кошелька uQ   ⚠️  Нет данных для сохранения после анализа)r   r   r   r   r   r7   r'   r   rj   r[   rt   r   r   )r   raw_transactionsr   rn   r   all_db_transactionsr    r   updated_transactionssorted_transactionsrS   rR   tx_typerZ   
updated_txdb_txsuccesss                    r   analyze_wallet_transactionsr   _  sS    IJ t$L 3b$~.K"&&9J2KIY'..r2	3   ,113 (.|!$\7VW & 	4B&&2K{A.IffVnG#B  VVK0VVK0&*vve}	J !''
3!	4&  BBVW ' 	.B"0#(VVK4vr*&&*VVK3VVK3!vvmQ7vveQ'ffT1oE  &&u-	.7(.V ()<=6~6FFnors  pA  oB  BQ  R  Sno}n~  Aabr   c                    t        |       }|d   D cg c]  }|d   	 }}t        |      }t        |d         }t        |d   D cg c]  }|j                  d      s| c}      }t	        |      }t        |      }	t        |      }
t        |      }t        ||      }t        ||      }||||	|
|||||d
}|S c c}w c c}w )Nr)   r    r   )
r   r   len_all_buys_in_valid_mcmax_tokens_per_hourhold_time_percentmin_buy_percentr   created_tokens_percentr   r   )
r   r<   r   r7   r   r   r   r   r   r   )r   r   r   
token_listr   r   r    r   r   r   r   r   r   r   metricss                  r   wallet_metricsr     s    6v>M:G:QR;+g&RJR7
CK ]8,-J&)mH>U*vUY^YbYbctYu5*v&w#9-H1-@7F)-8O-m[I7{S !+J$<2.*."8&"G N5 S
 +ws   B;C C returnc                 4   | d   }| d   }| d   }| d   }| d   }| d   }| d   }| d   }| d	   }	| d
   }
t         }t        }|dk  rd}nt        }|dk  rd}d}nt        }t        }||k  }||k\  }||k\  }||k\  }||k  }t        ||||||||	|
	      }||||||||dS )Nr   r   r   r   r   r   r   r   r   r   r"   2   )token_amounttokens_in_MCf_tokens_phf_hold_timef_minbuyf_before_migf_created_tokenswallet_type)MAX_TOKENS_PER_HOUR#MIN_TOKENS_BEFORE_MIGRATION_PERCENTMIN_NORMAL_BUYS_PERCENTMIN_HOLD_TIME_PERCENTMAX_CREATED_PERCENT_PERCENTr   )r   r   r   r   r   r   r   r   r   r   r   passed_max_tokens_per_hourpassed_migration_percentpassed_min_buy_percentpassed_hold_time_percentpassed_created_tokens_percentr   r   r   r   r   wallet_classs                         r   apply_filtersr    s8   &J&-.O&P# '(B C!"78 34/0O 34$%=>O,M-(K!4B1$!#!8&!+#% (*%#8 (C%26PP*.FF&*@@*.FF48UU!' 
L #7*(#)2#	 	r   c                     	 t        |       }t        |      }|r| |d<   |d   |d<   |d   |d<   |d   |d<   |S # t        $ r}t        d|  d	|        Y d
}~y
d
}~ww xY w)u  
    Основная функция для анализа кошелька.
    Получает метрики, применяет фильтры и возвращает результат классификации.
    
    Args:
        wallet_address: адрес кошелька для анализа
    
    Returns:
        dict: результат анализа с типом кошелька и метриками
    r   r
  rb   r  r   r  r   u4   Ошибка при анализе кошелька z: N)r   r  r   r   )r   r   r   r   s       r   analyze_walletr    s     0 w'-F8#M2F6N#).#9F< 8>~8NF45 D^DTTVWXVYZ[s   69 	AAA)1collectionsr   clickhouse_driverr   sysospathr'   abspathjoindirname__file__API.coingeckoAPIr   
API.jupAPIr   utils.configutils.ClickHouseManagerr   typingr	   r
   r   r   r   r   r.   r5   r<   rP   r[   rt   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   strr  r  rB   r   r   <module>r(     s    # $ 
 	 RWW__X-F MN O )   6 , ,>!F#>
4.1B$kT(\%N#&J@ DFX/t>Pd>6htCH~6 6pr   