o
    špj4@  ã                   @   sÒ  U d dl Z d dlZd dlZe e¡Ze j dd¡ee j dd¡ƒe j dd¡e j dd	¡e j d
d¡dddœZ	da
ejdB ed< dd„ Zdd„ ZdCdd„Zdeddfdd„Zdeddfdd„ZdCdd„ZdedB fdd „Zdee fd!d"„Zd#eddfd$d%„Zdeeef fd&d'„Zd(ed)eddfd*d+„Zd(ededB fd,d-„Zd.ed/eddfd0d1„Zd.edefd2d3„Zd4ed5ed6edB ddfd7d8„Z dee fd9d:„Z!d4edefd;d<„Z"d=edefd>d?„Z#d@eddfdAdB„Z$dS )Dé    NÚDB_HOSTzofficialsite.krÚDB_PORTi
[  ÚDB_USERÚadminÚDB_PASSWORDz	dlgks~123ÚDB_NAMEÚautotradingÚutf8mb4T)ÚhostÚportÚuserÚpasswordÚdbÚcharsetÚ
autocommitÚ_poolc                  Ã   sò  �t jddddœt¤ŽI dH at ¡ 4 I dH šÐ} |  ¡ 4 I dH š²}| d¡I dH  dD ]0}z| d|› �¡I dH  W q+ ty[ } zt|ƒ 	¡ }d|vrQd	|vrQ‚ W Y d}~q+d}~ww | d
¡I dH  | d¡I dH  z
| d¡I dH  W n! ty— } zt|ƒ 	¡ }d|vr�d	|vr�‚ W Y d}~nd}~ww | d¡I dH  | d¡I dH  | d¡I dH  | d¡I dH  | d¡I dH  | d¡I dH  W d  ƒI dH  n1 I dH sØw   Y  W d  ƒI dH  n1 I dH síw   Y  t
 d¡ dS )u*   ì»¤ë„¥ì…˜ í’€ ìƒ�ì„± + í…Œì�´ë¸” ì´ˆê¸°í™”é   é   )ÚminsizeÚmaxsizeNa¹  
                CREATE TABLE IF NOT EXISTS trading_session (
                    id INT PRIMARY KEY DEFAULT 1,
                    running TINYINT NOT NULL DEFAULT 0,
                    total_budget DOUBLE NOT NULL DEFAULT 0,
                    compound TINYINT NOT NULL DEFAULT 0,
                    total_realized DOUBLE NOT NULL DEFAULT 0,
                    total_trades INT NOT NULL DEFAULT 0,
                    started_at VARCHAR(30),
                    paper_mode TINYINT NULL DEFAULT NULL,
                    virtual_krw DOUBLE NULL DEFAULT NULL,
                    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
                )
            )z/ADD COLUMN paper_mode TINYINT NULL DEFAULT NULLz/ADD COLUMN virtual_krw DOUBLE NULL DEFAULT NULLzALTER TABLE trading_session Ú	duplicateÚexistsa+  
                CREATE TABLE IF NOT EXISTS positions (
                    ticker VARCHAR(20) PRIMARY KEY,
                    coin VARCHAR(10) NOT NULL,
                    status VARCHAR(10) NOT NULL,
                    buy_price DOUBLE,
                    buy_volume DOUBLE,
                    bought_at VARCHAR(20),
                    target_profit DOUBLE NOT NULL,
                    stop_loss DOUBLE NOT NULL,
                    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
                )
            a�  
                CREATE TABLE IF NOT EXISTS alerts (
                    id INT PRIMARY KEY,
                    chat_id BIGINT NOT NULL,
                    symbol VARCHAR(20) NOT NULL,
                    target_price DOUBLE NOT NULL,
                    direction VARCHAR(10) NOT NULL,
                    price_unit VARCHAR(10) NOT NULL DEFAULT 'USD'
                )
            z…
                    ALTER TABLE alerts
                    ADD COLUMN price_unit VARCHAR(10) NOT NULL DEFAULT 'USD'
                a   
                CREATE TABLE IF NOT EXISTS bot_state (
                    name VARCHAR(50) PRIMARY KEY,
                    value VARCHAR(255) NOT NULL,
                    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
                )
            aÀ  
                CREATE TABLE IF NOT EXISTS app_event_deliveries (
                    event_key VARCHAR(191) PRIMARY KEY,
                    event_type VARCHAR(30) NOT NULL,
                    app_key VARCHAR(80) NOT NULL,
                    event_time DATETIME NULL,
                    delivered_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
                    INDEX idx_app_event_delivered_at (delivered_at)
                )
            z{
                DELETE FROM app_event_deliveries
                WHERE delivered_at < NOW() - INTERVAL 90 DAY
            aQ  
                CREATE TABLE IF NOT EXISTS notification_subscribers (
                    chat_id BIGINT PRIMARY KEY,
                    display_name VARCHAR(100) NOT NULL DEFAULT '',
                    username VARCHAR(100),
                    subscribed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
                )
            a�  
                CREATE TABLE IF NOT EXISTS notification_invites (
                    token_hash CHAR(64) PRIMARY KEY,
                    created_by BIGINT NOT NULL,
                    expires_at DATETIME NOT NULL,
                    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
                    INDEX idx_notification_invites_expires_at (expires_at)
                )
            zW
                DELETE FROM notification_invites WHERE expires_at < NOW()
            zDB initialized© )ÚaiomysqlÚcreate_poolÚ	DB_CONFIGr   ÚacquireÚcursorÚexecuteÚ	ExceptionÚstrÚlowerÚloggerÚinfo)ÚconnÚcurÚ
column_sqlÚeÚerrr   r   ú,/var/www/back/telegram_server/persistence.pyÚinit_db   sJ   €ÿÿ€ý
€ý
	*¡(ÿcr*   c                   Ã   s(   �t rt  ¡  t  ¡ I d H  d a d S d S )N)r   ÚcloseÚwait_closedr   r   r   r)   Úclose_db�   s   €ýr-   Úreturnc                 Ã   s.  �t sdS zvt  ¡ 4 I dH š`}| ¡ 4 I dH š@}| dt| jƒ| jt| jƒ| j| j	| j
t| jƒ| jt| jƒ| jt| jƒ| j| j	| j
t| jƒ| jf¡I dH  W d  ƒI dH  n1 I dH s]w   Y  W d  ƒI dH  W dS 1 I dH stw   Y  W dS  ty– } zt d|› �¡ W Y d}~dS d}~ww )u#   íŠ¸ë ˆì�´ë”© ì„¸ì…˜ ì €ìž¥ (upsert)Na  
                    INSERT INTO trading_session (
                        id, running, total_budget, compound, total_realized,
                        total_trades, started_at, paper_mode, virtual_krw
                    )
                    VALUES (1, %s, %s, %s, %s, %s, %s, %s, %s)
                    ON DUPLICATE KEY UPDATE
                        running=%s, total_budget=%s, compound=%s,
                        total_realized=%s, total_trades=%s, started_at=%s,
                        paper_mode=%s, virtual_krw=%s
                zsave_session error: )r   r   r   r   ÚintÚrunningÚtotal_budgetÚcompoundÚtotal_realizedÚtotal_tradesÚ
started_atÚ
paper_modeÚ_virtual_krwr   r"   Úerror)Útraderr$   r%   r'   r   r   r)   Úsave_session‰   s*   €úö*ÿ2ÿ€ÿr:   Úposc                 Ã   s6  �t sd S zzt  ¡ 4 I d H šd}| ¡ 4 I d H šD}| d| d | d | d |  d¡|  d¡|  d¡| d | d	 | d |  d¡|  d¡|  d¡| d | d	 f¡I d H  W d   ƒI d H  n1 I d H saw   Y  W d   ƒI d H  W d S 1 I d H sxw   Y  W d S  tyš } zt d
|› �¡ W Y d }~d S d }~ww )Na{  
                    INSERT INTO positions (ticker, coin, status, buy_price, buy_volume, bought_at, target_profit, stop_loss)
                    VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
                    ON DUPLICATE KEY UPDATE
                        status=%s, buy_price=%s, buy_volume=%s, bought_at=%s,
                        target_profit=%s, stop_loss=%s
                ÚtickerÚcoinÚstatusÚ	buy_priceÚ
buy_volumeÚ	bought_atÚtarget_profitÚ	stop_losszsave_position error: )r   r   r   r   Úgetr   r"   r8   )r;   r$   r%   r'   r   r   r)   Úsave_position¦   s(   €ûú*ÿ2ÿ€ÿrE   r<   c              
   Ã   sØ   �t sd S zKt  ¡ 4 I d H š5}| ¡ 4 I d H š}| d| f¡I d H  W d   ƒI d H  n1 I d H s2w   Y  W d   ƒI d H  W d S 1 I d H sIw   Y  W d S  tyk } zt d|› �¡ W Y d }~d S d }~ww )Nz'DELETE FROM positions WHERE ticker = %szdelete_position error: ©r   r   r   r   r   r"   r8   )r<   r$   r%   r'   r   r   r)   Údelete_position½   s   €*ÿ2ÿ€ÿrG   c               
   Ã   sÔ   �t sd S zIt  ¡ 4 I d H š3} |  ¡ 4 I d H š}| d¡I d H  W d   ƒI d H  n1 I d H s0w   Y  W d   ƒI d H  W d S 1 I d H sGw   Y  W d S  tyi } zt d|› �¡ W Y d }~d S d }~ww )NzDELETE FROM positionszclear_positions error: rF   ©r$   r%   r'   r   r   r)   Úclear_positionsÈ   s   €*ÿ2ÿ€ÿrI   c               
   Ã   sü   �t sd S z]t  ¡ 4 I d H šG} |  tj¡4 I d H š%}| d¡I d H  | ¡ I d H W  d   ƒI d H  W  d   ƒI d H  W S 1 I d H sDw   Y  W d   ƒI d H  W d S 1 I d H s[w   Y  W d S  ty} } zt 	d|› �¡ W Y d }~d S d }~ww )Nz:SELECT * FROM trading_session WHERE id = 1 AND running = 1zload_session error: ©
r   r   r   r   Ú
DictCursorr   Úfetchoner   r"   r8   rH   r   r   r)   Úload_sessionÓ   s"   €þÿ2ÿ€þrM   c               
   Ã   óþ   �t sg S z]t  ¡ 4 I d H šG} |  tj¡4 I d H š%}| d¡I d H  | ¡ I d H W  d   ƒI d H  W  d   ƒI d H  W S 1 I d H sDw   Y  W d   ƒI d H  W d S 1 I d H s[w   Y  W d S  ty~ } zt 	d|› �¡ g W  Y d }~S d }~ww )NzSELECT * FROM positionszload_positions error: ©
r   r   r   r   rK   r   Úfetchallr   r"   r8   rH   r   r   r)   Úload_positionsà   s"   €þÿ2ÿ€þrQ   Úalertsc                 Ã   s&  �t sd S zrt  ¡ 4 I d H š\}| ¡ 4 I d H š<}| d¡I d H  |  ¡ D ]$\}}|D ]}| d|d ||d |d |d | dd¡f¡I d H  q*q$W d   ƒI d H  n1 I d H sYw   Y  W d   ƒI d H  W d S 1 I d H spw   Y  W d S  ty’ } zt d	|› �¡ W Y d }~d S d }~ww )
NzDELETE FROM alertszhINSERT INTO alerts (id, chat_id, symbol, target_price, direction, price_unit) VALUES (%s,%s,%s,%s,%s,%s)ÚidÚsymbolÚtarget_priceÚ	directionÚ
price_unitÚUSDzsave_alerts error: )	r   r   r   r   ÚitemsrD   r   r"   r8   )rR   r$   r%   Úchat_idÚ
alert_listÚar'   r   r   r)   Úsave_alertsí   s6   €
úþÿÿ*þ2ÿ€ÿr]   c               
   Ã   sP  �t si dfS z‚t  ¡ 4 I dH š:} |  tj¡4 I dH š}| d¡I dH  | ¡ I dH }W d  ƒI dH  n1 I dH s;w   Y  W d  ƒI dH  n1 I dH sPw   Y  i }d}|D ])}|d }| |g ¡ |d |d |d |d | 	d	¡pyd
dœ¡ t
||d ƒ}q[||fW S  ty§ } zt d|› �¡ i dfW  Y d}~S d}~ww )z#Returns (alerts_dict, max_alert_id)r   NzSELECT * FROM alertsrZ   rS   rT   rU   rV   rW   rX   )rS   rT   rU   rV   rW   zload_alerts error: )r   r   r   r   rK   r   rP   Ú
setdefaultÚappendrD   Úmaxr   r"   r8   )r$   r%   ÚrowsrR   Úmax_idÚrrZ   r'   r   r   r)   Úload_alerts  s6   €*þ(ÿü
€þrd   ÚnameÚvaluec              
   Ã   sâ   �t sd S zMt  ¡ 4 I d H š7}| ¡ 4 I d H š}| d| ||f¡I d H  W d   ƒI d H  n1 I d H s4w   Y  W d   ƒI d H  W d S 1 I d H sKw   Y  W d S  typ } zt d| › d|› �¡ W Y d }~d S d }~ww )Nz¤
                    INSERT INTO bot_state (name, value)
                    VALUES (%s, %s)
                    ON DUPLICATE KEY UPDATE value = %s
                zsave_bot_state error [ú]: rF   )re   rf   r$   r%   r'   r   r   r)   Úsave_bot_state  s   €ü*ÿ2ÿ$€ÿrh   c              
   Ã   s>  �t sd S z{t  ¡ 4 I d H še}| tj¡4 I d H šC}| d| f¡I d H  | ¡ I d H }|rF|d W  d   ƒI d H  W  d   ƒI d H  W S 	 W d   ƒI d H  W d   ƒI d H  W d S 1 I d H sbw   Y  W d   ƒI d H  W d S 1 I d H syw   Y  W d S  tyž } zt 	d| › d|› �¡ W Y d }~d S d }~ww )Nz+SELECT value FROM bot_state WHERE name = %srf   zload_bot_state error [rg   rJ   )re   r$   r%   Úrowr'   r   r   r)   Úload_bot_state.  s,   €üÿûÿ2ÿ€þrj   Ú
token_hashÚ
created_byc              
   Ã   s¶   �t stdƒ‚t  ¡ 4 I d H š?}| ¡ 4 I d H š }| d|f¡I d H  | d| |f¡I d H  W d   ƒI d H  n1 I d H s>w   Y  W d   ƒI d H  d S 1 I d H sTw   Y  d S )NúDB is not initializedzLDELETE FROM notification_invites WHERE created_by = %s OR expires_at < NOW()z¬
                INSERT INTO notification_invites (token_hash, created_by, expires_at)
                VALUES (%s, %s, DATE_ADD(NOW(), INTERVAL 15 MINUTE))
                ©r   ÚRuntimeErrorr   r   r   )rk   rl   r$   r%   r   r   r)   Úcreate_notification_invite>  s   €
þû*û.ÿrp   c              
   Ã   óº   �t sdS t  ¡ 4 I d H šC}| ¡ 4 I d H š$}| d| f¡I d H  |jdkW  d   ƒI d H  W  d   ƒI d H  S 1 I d H s@w   Y  W d   ƒI d H  d S 1 I d H sVw   Y  d S )NFz€
                DELETE FROM notification_invites
                WHERE token_hash = %s AND expires_at >= NOW()
                r   ©r   r   r   r   Úrowcount)rk   r$   r%   r   r   r)   Úconsume_notification_inviteP  s   €
ûøÿ.ÿrt   rZ   Údisplay_nameÚusernamec              
   Ã   s¨   �t stdƒ‚t  ¡ 4 I d H š8}| ¡ 4 I d H š}| d| ||||f¡I d H  W d   ƒI d H  n1 I d H s7w   Y  W d   ƒI d H  d S 1 I d H sMw   Y  d S )Nrm   zÕ
                INSERT INTO notification_subscribers (chat_id, display_name, username)
                VALUES (%s, %s, %s)
                ON DUPLICATE KEY UPDATE display_name = %s, username = %s
                rn   )rZ   ru   rv   r$   r%   r   r   r)   Úsave_notification_subscriber_  s   €ú*ÿ.ÿrw   c               
   Ã   rN   )Nz¼
                    SELECT chat_id, display_name, username, subscribed_at
                    FROM notification_subscribers
                    ORDER BY subscribed_at
                    z%load_notification_subscribers error: rO   rH   r   r   r)   Úload_notification_subscribersr  s&   €
ÿøÿ2ÿ
€þrx   c              
   Ã   rq   )NFz7DELETE FROM notification_subscribers WHERE chat_id = %sr   rr   )rZ   r$   r%   r   r   r)   Údelete_notification_subscriber…  s   €
þûÿ.ÿry   Ú	event_keyc              
   Ã   sú   �t sdS z_t  ¡ 4 I d H šI}| ¡ 4 I d H š)}| d| f¡I d H  | ¡ I d H d uW  d   ƒI d H  W  d   ƒI d H  W S 1 I d H sFw   Y  W d   ƒI d H  W d S 1 I d H s]w   Y  W d S  ty| } zt d| › d|› �¡ ‚ d }~ww )NFz?SELECT 1 FROM app_event_deliveries WHERE event_key = %s LIMIT 1zhas_app_event_delivery error [rg   )r   r   r   r   rL   r   r"   r8   )rz   r$   r%   r'   r   r   r)   Úhas_app_event_delivery‘  s(   €
þûÿ2ÿ€þr{   Úeventc                 Ã   s  �t sd S zrt  ¡ 4 I d H š\}| ¡ 4 I d H š<}| dt|  d¡p"dƒd d… t|  d¡p.dƒd d… t|  d¡p:dƒd d	… |  d
¡f¡I d H  W d   ƒI d H  n1 I d H sYw   Y  W d   ƒI d H  W d S 1 I d H spw   Y  W d S  tyŽ } zt d|  d¡|¡ ‚ d }~ww )NzÀ
                    INSERT IGNORE INTO app_event_deliveries
                      (event_key, event_type, app_key, event_time)
                    VALUES (%s, %s, %s, %s)
                    rz   Ú é¿   Ú
event_typeÚunknowné   Úapp_keyéP   Ú
event_timez'mark_app_event_delivered error [%s]: %s)	r   r   r   r   r    rD   r   r"   r8   )r|   r$   r%   r'   r   r   r)   Úmark_app_event_delivered¡  s2   €üú*ÿ2ÿý€úr…   )r.   N)%ÚosÚloggingr   Ú	getLoggerÚ__name__r"   ÚenvironrD   r/   r   r   ÚPoolÚ__annotations__r*   r-   r:   ÚdictrE   r    rG   rI   rM   ÚlistrQ   r]   Útuplerd   rh   rj   rp   Úboolrt   rw   rx   ry   r{   r…   r   r   r   r)   Ú<module>   sP   
 
ù
m

ÿþý
ü