File size: 7,477 Bytes
fc115d5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
"""
Server-side Binance Testnet Integration
Uses BinanceConnector on the local server (direct testnet access, no proxy needed).
"""

import streamlit as st
import os
from src.api.binance import BinanceConnector
import pandas as pd


def render_testnet_tab_server(api_key: str, api_secret: str):
    """
    Render testnet tab with server-side API calls.
    Requires the server to run locally (direct access to testnet.binance.vision).
    """
    try:
        api_key = api_key.strip() if api_key else ''
        api_secret = api_secret.strip() if api_secret else ''

        if not api_key or not api_secret:
            st.error("โŒ API keys are empty after sanitization!")
            return

        if len(api_key) < 20 or len(api_secret) < 20:
            st.error(f"โŒ API keys seem too short (key: {len(api_key)}, secret: {len(api_secret)})")
            return

        st.info(f"๐Ÿ”‘ API Key: {api_key[:8]}...{api_key[-4:]} ({len(api_key)} chars)")

        testnet = BinanceConnector(
            api_key=api_key,
            api_secret=api_secret,
            testnet=True
        )

        # Test connectivity
        try:
            connectivity = testnet.test_connectivity()
            if connectivity:
                st.success("โœ… Connected to Binance Testnet")
            else:
                st.warning("โš ๏ธ Connectivity test returned false, but trying anyway...")
        except Exception as e:
            st.error(f"โŒ Connectivity test failed: {e}")
            import traceback
            st.code(traceback.format_exc())
            return

        # Get balances
        try:
            balances = testnet.get_all_balances()
        except Exception as e:
            st.error(f"โŒ Failed to get balances: {e}")
            import traceback
            st.code(traceback.format_exc())
            return

        if not balances:
            st.error("โŒ No balances found. Account might be empty or API keys invalid.")
            st.warning("๐Ÿ’ก Tip: Go to testnet.binance.vision and claim test funds")
            return

        st.info(f"๐Ÿ“Š Retrieved {len(balances)} balance entries")

        # Calculate portfolio value
        portfolio_value = 0.0
        positions_data = []
        usdt_balance = 0.0

        for currency, amounts in balances.items():
            total = float(amounts.get('total', 0))
            if total > 0:
                if currency == 'USDT':
                    portfolio_value += total
                    usdt_balance = float(amounts.get('free', 0))
                else:
                    try:
                        ticker = testnet.get_ticker(f"{currency}/USDT")
                        price = float(ticker.get('last', 0))
                        if price > 0:
                            value_usdt = total * price
                            portfolio_value += value_usdt
                            positions_data.append({
                                'Asset': currency,
                                'Amount': f"{total:.6f}",
                                'Price': f"${price:,.2f}",
                                'Value (USDT)': f"${value_usdt:,.2f}"
                            })
                    except Exception:
                        pass

        # Portfolio overview
        col1, col2, col3 = st.columns(3)
        with col1:
            st.metric(
                label="๐Ÿ’ฐ Portfolio Value",
                value=f"${portfolio_value:,.2f}",
                delta=None
            )
        with col2:
            st.metric(label="๐Ÿ’ต USDT Balance", value=f"${usdt_balance:,.2f}")
        with col3:
            st.metric(
                label="๐Ÿ“Š Total P&L %",
                value="N/A",
                delta=None
            )

        st.markdown("---")

        if positions_data:
            st.markdown("### ๐Ÿ“Š Current Positions")
            st.dataframe(pd.DataFrame(positions_data), use_container_width=True, hide_index=True)
        else:
            st.info("No open positions. Portfolio is 100% USDT")

        st.markdown("---")

        # Trading controls
        st.markdown("### ๐ŸŽฎ Trading Controls")
        col1, col2 = st.columns(2)
        with col1:
            trade_symbol = st.selectbox(
                "Select Pair",
                options=['BTC/USDT', 'ETH/USDT', 'SOL/USDT', 'XRP/USDT'],
                key="testnet_symbol"
            )
        with col2:
            trade_amount = st.number_input(
                "Amount (USDT)",
                min_value=10.0,
                max_value=float(usdt_balance) if usdt_balance > 10 else 10000.0,
                value=100.0,
                step=10.0,
                key="testnet_amount"
            )

        col1, col2, col3 = st.columns(3)

        if col1.button("๐ŸŸข BUY (Market)", key="testnet_buy", use_container_width=True):
            try:
                ticker = testnet.get_ticker(trade_symbol)
                current_price = float(ticker['last'])
                amount_base = trade_amount / current_price
                order = testnet.place_market_order(symbol=trade_symbol, side='buy', amount=amount_base)
                if order:
                    st.success(f"โœ… BUY order placed: {amount_base:.6f} {trade_symbol.split('/')[0]} @ ${current_price:,.2f}")
                    st.rerun()
                else:
                    st.error("โŒ Order failed")
            except Exception as e:
                st.error(f"โŒ Order failed: {e}")

        if col2.button("๐Ÿ”ด SELL (Market)", key="testnet_sell", use_container_width=True):
            try:
                base_currency = trade_symbol.split('/')[0]
                base_balance = balances.get(base_currency, {}).get('free', 0)
                if float(base_balance) == 0:
                    st.warning(f"No {base_currency} to sell")
                else:
                    order = testnet.place_market_order(symbol=trade_symbol, side='sell', amount=float(base_balance))
                    if order:
                        st.success(f"โœ… SELL order placed: {base_balance} {base_currency}")
                        st.rerun()
                    else:
                        st.error("โŒ Order failed")
            except Exception as e:
                st.error(f"โŒ Order failed: {e}")

        if col3.button("๐Ÿ“‹ Open Orders", key="testnet_orders", use_container_width=True):
            try:
                open_orders = testnet.get_open_orders()
                if open_orders:
                    st.write(open_orders)
                else:
                    st.info("No open orders")
            except Exception as e:
                st.error(f"โŒ Failed to fetch orders: {e}")

        st.markdown("---")
        st.markdown("### โ„น๏ธ Testnet Information")
        info_col1, info_col2 = st.columns(2)
        with info_col1:
            st.info("""
            **About Testnet:**
            - Zero real money risk
            - Test trading strategies
            - Same API as production
            - Perfect for learning
            """)
        with info_col2:
            st.warning("""
            **Important Notes:**
            - Using testnet.binance.vision
            - Testnet funds reset periodically
            - Use for testing only
            - Get free testnet funds from Binance
            """)

    except Exception as e:
        st.error(f"โŒ Error: {e}")
        import traceback
        st.code(traceback.format_exc())