PageSourceSearch

https://entrade.com.vn/js/avatar.js

js entrade.com.vn collected 2026-10-05 23:06:07 UTC 8,685 bytes, 228 lines download raw bytes

1var env = "production"; // MUST set Real tab in Leaderboard section to active at init to not get error
2
3function toggleFaq(element) { // This should work as long as the FAQ section have at most 1 active element at start
4    const faqItem = element.parentElement;
5    const isActive = faqItem.classList.contains('active');
6
7    if (isActive) {
8        faqItem.classList.remove('active');
9        return;
10    }
11
12    // Close current active item then set chosen element to 'active'
13    const active_el = document.querySelector('.faq-item.active');
14    if (active_el)
15        active_el.classList.remove('active');
16
17    faqItem.classList.add('active');
18}
19
20function convertDateTime(isoString) {
21    // Parse the ISO string to a Date object
22    const date = new Date(isoString);
23
24    // Extract day, month, year
25    const day = String(date.getUTCDate()).padStart(2, '0');
26    const month = String(date.getUTCMonth() + 1).padStart(2, '0'); // Months are 0-based
27    const year = date.getUTCFullYear();
28
29    return `${day}/${month}/${year}`;
30}
31
32async function fetchLeaderboard() { // This should work as long as the Leaderboard section have buttons with textContent (1W/1M/3M/6M/1Y)
33    const active_el = document.querySelector('.time-btn.active');
34    const URL = `https://services.entrade.com.vn/bot-api/leaderboard?env=${env}&time=${active_el.textContent}`;
35
36    const response = await fetch(URL);
37    if (response.ok) {
38        const data = await response.json();
39        return data;
40    }
41
42    return null;
43}
44
45async function updateLeaderboard(json) {
46    start_date = convertDateTime(json.from.replace('Z', '-07:00'));
47    end_date = convertDateTime(json.lastUpdated.replace('Z', '-07:00'));
48
49    const update_date_tag = document.querySelector(".leaderboard-date");
50    update_date_tag.textContent = `Từ ${start_date} đến ${end_date}`
51
52    const leaderboard = document.getElementById("leaderboard-tbody");
53    leaderboard.replaceChildren(); // Delete current board
54
55    json.data.forEach((item, idx) => {
56        const row = document.createElement("tr");
57
58        // Process rank
59        const rank = document.createElement("td");
60        rank.classList.add("rank-cell")
61        if (idx == 0)
62            rank.textContent = "🥇";
63        else if (idx == 1)
64            rank.textContent = "🥈";
65        else if (idx == 2)
66            rank.textContent = "🥉";
67        else
68            rank.textContent = idx + 1;
69
70        row.appendChild(rank);
71
72        // Process name
73        const name = document.createElement("td");
74        name.classList.add("name-cell")
75        name.innerHTML = `<span>${item.strategyName}</span>`;
76        row.appendChild(name);
77
78        // Process position
79        const position = document.createElement("td");
80        position.classList.add("position-cell");
81
82        if (item.botType == "LONG") 
83            position.innerHTML = '<span class="position-badge buy"><i class="fas fa-arrow-up"></i>MUA</span>';
84        else
85            position.innerHTML = '<span class="position-badge sell"><i class="fas fa-arrow-down"></i>BÁN</span>';
86
87        row.appendChild(position);
88
89        // Process indicator
90        const indicator = document.createElement("td");
91        indicator.classList.add("indicators-cell");
92
93        const indicators_arr = item.indicators;
94        for (let i = 0; i < indicators_arr.length; ++i) {
95            const span = document.createElement("span");
96            span.classList.add("indicator-tag");
97            if (i < 3) {
98                span.innerText = indicators_arr[i];
99                indicator.appendChild(span);
100            }
101            else {
102                span.innerText = "...";
103                indicator.appendChild(span);
104                break;
105            }
106        }
107        row.appendChild(indicator);
108
109        // Process profit
110        const profit = document.createElement("td");
111        profit.classList.add("profit-cell");
112        profit.innerText = item.netPoints.toFixed(2);
113        row.appendChild(profit);
114
115        // Include everything
116        leaderboard.appendChild(row);
117    })
118}
119
120document.querySelectorAll('.time-btn').forEach(el => {
121    el.addEventListener("click", async () => {
122        const active_el = document.querySelector('.time-btn.active');
123        if (active_el != el) {
124            active_el.classList.remove('active');
125            el.classList.add('active');
126
127            const data = await fetchLeaderboard();
128            if (data)
129                updateLeaderboard(data);
130        }
131    });
132});
133
134document.querySelectorAll(".tab-btn").forEach(el => {
135    el.addEventListener("click", async () => {
136        const active_el = document.querySelector('.tab-btn.active');
137        if (active_el != el) {
138            active_el.classList.remove('active');
139            el.classList.add('active');
140            env = (env == "production") ? "papertrade" : "production";
141
142            const data = await fetchLeaderboard();
143            if (data)
144                updateLeaderboard(data);
145        }
146    });
147});
148
149class AvatarBot {
150    constructor(id, name, profit_rate, tag, feature_img, description="", version=1) {
151        this.id = id;
152        this.name = name;
153        this.profit_rate = profit_rate;
154        this.tag = tag;
155        this.feature_img = feature_img;
156        this.version = version;
157        this.description = description;
158    }
159}
160
161function GenerateBotCard(bot) {
162    return `
163        <div style="width: 320px; height: 180px; background: white; color: #111; border-radius: 16px; border: 1px solid #ddd; box-shadow: 0 6px 16px rgba(0, 0, 0, 0.5);">
164
165            <div style="display: flex; justify-content: space-between; margin: 10px; align-items: center">
166                <div class="bot-name">${bot.name}</div>
167                <div class="tooltip-container" style="width: 16px; height: 16px; color: #0066cc; border: 1px solid #0066cc; border-radius: 50%; text-align: center; line-height: 16px; font-size: 8px; font-weight: 900">
168                    i
169                    <div class="tooltip">
170                        ${bot.description.replace(/\n/g, '<br>')}
171                    </div>
172                </div>
173            </div>
174
175            <div style="display: flex; gap: 10px; margin: 10px">
176                <div style="display: flex; width: 100x; flex-shrink: 0; text-align: center; flex-direction: column; justify-content: space-between; align-items: center">
177                    <div>
178                        <span style="font-size: 30px; font-weight: bold; color: #00cc00; line-height: 1">${bot.profit_rate}%</span>
179                        <span style="font-size: 6px; color: #666; vertical-align: top; line-height: 2">/năm</span>
180                    </div>
181
182                    <div style="width: 100%; background: ${(bot.tag === "Long") ? "#00cc00" : (bot.tag === "Short") ? "#ff6600" : "gold"}; color: white; padding: 6px 18px; border-radius: 999px; font-weight: bold; font-size: 10px">${bot.tag}</div>
183                </div>
184
185                <div style="flex: 1; height: 77px; background: #f8f9fa; border-radius: 6px">
186                    <img src=${bot.feature_img} style="width: 100%; height: 100%; object-fit: fill">
187                </div>
188            </div>
189
190            <div style="display: flex; justify-content: center">
191                <button class="copy-bot-btn"
192                onclick="window.open('https://avatar.entrade.com.vn/tao-chien-thuat?strategyId=${bot.id}&strategyVersion=${bot.version}', '_blank')">
193                    + Copy ngay!
194                </button>
195            </div>
196        </div>
197    `;
198}
199
200function renderBots(bot_list, page=1, bot_per_page=8) {
201    const grid = document.querySelector('.bot-avatar-leaderboard .bot-grid');
202    if (!grid) return;
203
204    const start_index = bot_per_page * (page - 1);
205    const filteredBots = bot_list.slice(start_index, start_index + bot_per_page);
206
207    if (filteredBots.length === 0) {
208        grid.innerHTML = '<div style="padding:40px; font-size: 36px;">Chúng tôi đang trong quá trình chọn lọc các bot có hiệu quả nhất. Trong thời gian đó, xin vui lòng chọn cho mình chiến thuật khác.</div>';
209        return;
210    }
211
212    grid.innerHTML = filteredBots
213        .map(bot => GenerateBotCard(bot))
214        .join('');
215}
216
217document.querySelectorAll('.bot-avatar-leaderboard .tab').forEach(btn => {
218    btn.addEventListener('click', () => {
219
220        document.querySelectorAll('.bot-avatar-leaderboard .tab').forEach(b => b.classList.remove('active'));
221        btn.classList.add('active');
222
223        const tag = btn.getAttribute('data-tab');
224        const filteredBot = (tag === "all") ? bots : bots.filter(bot => bot.tag === tag);
225
226        renderBots(filteredBot);
227    });
228});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.