Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions IntelliTrader.Web/Views/Home/Dashboard.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,27 @@
</div>
</div>

<!-- Дополнительные настройки звука -->
<!-- Дополнительные настройки звука и порогов уведомлений -->
<div class="row align-items-center mt-2 pt-2" style="border-top: 1px solid var(--card-border); font-size: 13px;">
<div class="col-md-5 d-flex align-items-center mb-2 mb-md-0">
<div class="col-md-4 d-flex align-items-center mb-2 mb-md-0">
<i class="fas fa-sliders-h mr-2" style="color: #7aa2f7;"></i>
<span class="mr-2" style="white-space: nowrap;">Громкость:</span>
<input type="range" id="soundVolumeSlider" min="0" max="1" step="0.05" value="0.5" style="flex-grow: 1; height: 4px; background: var(--bg-color); outline: none; transition: background 450ms ease-in-out; -webkit-appearance: none; cursor: pointer;" />
<span id="soundVolumeValue" class="ml-2" style="font-weight: bold; color: #7aa2f7; min-width: 40px; text-align: right;">50%</span>
</div>
<div class="col-md-5 d-flex align-items-center mb-2 mb-md-0">
<div class="col-md-4 d-flex align-items-center mb-2 mb-md-0">
<i class="fas fa-music mr-2" style="color: #bb9af3;"></i>
<span class="mr-2" style="white-space: nowrap;">Профиль звука:</span>
<span class="mr-2" style="white-space: nowrap;">Профиль:</span>
<select id="soundProfileSelect" class="form-control form-control-sm" style="background-color: var(--input-bg); color: var(--text-color); border: 1px solid var(--input-border); border-radius: 4px; height: 28px; padding: 2px 8px; font-size: 12px; width: auto;">
<option value="chime">Приятный звон (Chime)</option>
<option value="beep">Высокий писк (Beep)</option>
<option value="arcade">Ретро аркада (Arcade)</option>
</select>
</div>
<div class="col-md-2 text-md-right text-muted" style="font-size: 11px;">
Настройки звука
<div class="col-md-4 d-flex align-items-center mb-2 mb-md-0">
<i class="fas fa-filter mr-2" style="color: #e0af68;"></i>
<span class="mr-2" style="white-space: nowrap;">Мин. сделка USDT:</span>
<input type="number" id="minTradeSizeInput" min="0" step="1" value="0" class="form-control form-control-sm" style="background-color: var(--input-bg); color: var(--text-color); border: 1px solid var(--input-border); border-radius: 4px; height: 28px; padding: 2px 8px; font-size: 12px; width: 90px;" />
</div>
</div>
</div>
Expand All @@ -59,6 +61,7 @@
const soundVolumeSlider = document.getElementById("soundVolumeSlider");
const soundVolumeValue = document.getElementById("soundVolumeValue");
const soundProfileSelect = document.getElementById("soundProfileSelect");
const minTradeSizeInput = document.getElementById("minTradeSizeInput");
const notificationContainer = document.getElementById("notificationContainer");

let isSoundEnabled = localStorage.getItem("realtime_sound_enabled") !== "false";
Expand All @@ -74,10 +77,16 @@
// Load sound profile with fallback to 'chime'
let soundProfile = localStorage.getItem("realtime_sound_profile") || "chime";

// Load minimum USDT trade size threshold with fallback to 0
let minTradeSize = parseFloat(localStorage.getItem("realtime_min_trade_size")) || 0;

// Sync UI controls with values
soundVolumeSlider.value = soundVolume;
soundVolumeValue.textContent = Math.round(soundVolume * 100) + "%";
soundProfileSelect.value = soundProfile;
if (minTradeSizeInput) {
minTradeSizeInput.value = minTradeSize;
}

updateSoundButtonUI();

Expand Down Expand Up @@ -214,6 +223,14 @@
playNotificationSound();
});

if (minTradeSizeInput) {
minTradeSizeInput.addEventListener("change", function () {
minTradeSize = Math.max(0, parseFloat(minTradeSizeInput.value) || 0);
minTradeSizeInput.value = minTradeSize;
localStorage.setItem("realtime_min_trade_size", minTradeSize);
});
}

testSoundBtn.addEventListener("click", function () {
initAudio();
const prev = isSoundEnabled;
Expand Down Expand Up @@ -331,9 +348,12 @@
if (!knownTrades.has(tradeId)) {
knownTrades.add(tradeId);

const tradeUsdtSize = (parseFloat(trade.Amount) || 0) * (parseFloat(trade.SellPrice) || parseFloat(trade.AveragePrice) || 0);
if (!isFirstLoad) {
hasNewTrade = true;
showToastNotification(trade);
if (tradeUsdtSize >= minTradeSize) {
hasNewTrade = true;
showToastNotification(trade);
}
}
}
});
Expand Down
81 changes: 79 additions & 2 deletions IntelliTrader.Web/Views/Home/Settings.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,45 @@
<button class="btn btn-info settings-btn" onclick="restartServices();" @if (Model.ReadOnlyMode) { <text>disabled</text> }>Restart Services</button>

<div class="configs mt-4" style="background-color: var(--card-bg) !important; border: 1px solid var(--border-color) !important; color: var(--text-color) !important; padding: 20px; border-radius: 4px; margin-top: 20px;">
<h2>Оформление</h2>
<h2>Оформление и Уведомления</h2>
<div style="margin-bottom: 15px; display: flex; align-items: center;">
<label style="margin-right: 15px; margin-bottom: 0; font-weight: bold;">Тема оформления:</label>
<label style="margin-right: 15px; margin-bottom: 0; font-weight: bold; width: 220px;">Тема оформления:</label>
<select id="settingsThemeSelect" class="form-control form-control-sm" style="width: auto; background-color: var(--input-bg); color: var(--text-color); border: 1px solid var(--input-border); border-radius: 4px;">
<option value="dark">Темная (по умолчанию)</option>
<option value="light">Светлая</option>
</select>
</div>

<hr style="border-color: var(--border-color);" />

<h3>Настройки уведомлений реального времени</h3>
<div style="margin-bottom: 15px; display: flex; align-items: center;">
<label style="margin-right: 15px; margin-bottom: 0; font-weight: bold; width: 220px;">Звуковые оповещения:</label>
<select id="settingsSoundEnabledSelect" class="form-control form-control-sm" style="width: auto; background-color: var(--input-bg); color: var(--text-color); border: 1px solid var(--input-border); border-radius: 4px;">
<option value="true">Включено</option>
<option value="false">Выключено</option>
</select>
</div>

<div style="margin-bottom: 15px; display: flex; align-items: center;">
<label style="margin-right: 15px; margin-bottom: 0; font-weight: bold; width: 220px;">Громкость звука:</label>
<input type="range" id="settingsSoundVolumeSlider" min="0" max="1" step="0.05" value="0.5" style="width: 150px; height: 4px; background: var(--bg-color); outline: none; cursor: pointer;" />
<span id="settingsSoundVolumeValue" style="margin-left: 10px; font-weight: bold; color: #7aa2f7;">50%</span>
</div>

<div style="margin-bottom: 15px; display: flex; align-items: center;">
<label style="margin-right: 15px; margin-bottom: 0; font-weight: bold; width: 220px;">Звуковой профиль:</label>
<select id="settingsSoundProfileSelect" class="form-control form-control-sm" style="width: auto; background-color: var(--input-bg); color: var(--text-color); border: 1px solid var(--input-border); border-radius: 4px;">
<option value="chime">Приятный звон (Chime)</option>
<option value="beep">Высокий писк (Beep)</option>
<option value="arcade">Ретро аркада (Arcade)</option>
</select>
</div>

<div style="margin-bottom: 15px; display: flex; align-items: center;">
<label style="margin-right: 15px; margin-bottom: 0; font-weight: bold; width: 220px;">Мин. объем сделки (USDT):</label>
<input type="number" id="settingsMinTradeSizeInput" min="0" step="1" value="0" class="form-control form-control-sm" style="width: 120px; background-color: var(--input-bg); color: var(--text-color); border: 1px solid var(--input-border); border-radius: 4px;" />
</div>
</div>

<script>
Expand Down Expand Up @@ -87,6 +118,52 @@
}
});
}

// Notification Settings Synchronization
const soundEnabledSelect = document.getElementById("settingsSoundEnabledSelect");
const soundVolumeSlider = document.getElementById("settingsSoundVolumeSlider");
const soundVolumeValue = document.getElementById("settingsSoundVolumeValue");
const soundProfileSelect = document.getElementById("settingsSoundProfileSelect");
const minTradeSizeInput = document.getElementById("settingsMinTradeSizeInput");

if (soundEnabledSelect) {
const isEnabled = localStorage.getItem("realtime_sound_enabled") !== "false";
soundEnabledSelect.value = isEnabled ? "true" : "false";
soundEnabledSelect.addEventListener("change", function() {
localStorage.setItem("realtime_sound_enabled", soundEnabledSelect.value === "true");
});
}

if (soundVolumeSlider) {
let volume = parseFloat(localStorage.getItem("realtime_sound_volume"));
if (isNaN(volume)) volume = 0.5;
soundVolumeSlider.value = volume;
if (soundVolumeValue) soundVolumeValue.textContent = Math.round(volume * 100) + "%";

soundVolumeSlider.addEventListener("input", function() {
const val = parseFloat(soundVolumeSlider.value);
if (soundVolumeValue) soundVolumeValue.textContent = Math.round(val * 100) + "%";
localStorage.setItem("realtime_sound_volume", val);
});
}

if (soundProfileSelect) {
const profile = localStorage.getItem("realtime_sound_profile") || "chime";
soundProfileSelect.value = profile;
soundProfileSelect.addEventListener("change", function() {
localStorage.setItem("realtime_sound_profile", soundProfileSelect.value);
});
}

if (minTradeSizeInput) {
const minTradeSize = parseFloat(localStorage.getItem("realtime_min_trade_size")) || 0;
minTradeSizeInput.value = minTradeSize;
minTradeSizeInput.addEventListener("change", function() {
const val = Math.max(0, parseFloat(minTradeSizeInput.value) || 0);
minTradeSizeInput.value = val;
localStorage.setItem("realtime_min_trade_size", val);
});
}
});
</script>

Expand Down
33 changes: 32 additions & 1 deletion magda_agent_system/agent_tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@
},
{
"id": "web-dashboard-custom-alerts",
"status": "todo",
"status": "done",
"area": "web",
"risk": "low",
"title": "Add custom notification threshold settings on Dashboard",
Expand All @@ -473,6 +473,37 @@
"acceptance": [
"Order caching mechanism is integrated and avoids frequent disk reads for historical trade logs."
]
},
{
"id": "web-dashboard-export-trades-csv",
"status": "todo",
"area": "web",
"risk": "low",
"title": "Add trade history CSV export endpoint and Dashboard button",
"description": "Implement a controller endpoint to export trade history as downloadable CSV file and add an Export button on the Web Dashboard.",
"allowed_paths": [
"IntelliTrader.Web/Controllers/**",
"IntelliTrader.Web/Views/**",
"magda_agent_system/agent_tasks.json"
],
"acceptance": [
"Web Dashboard includes a button to export trade history as CSV file."
]
},
{
"id": "trading-signal-volatility-filter",
"status": "todo",
"area": "trading",
"risk": "medium",
"title": "Implement adaptive volatility filter for BuyProcessor signals",
"description": "Add an adaptive volatility filter to BuyProcessor to skip buy entries when signal volatility exceeds configurable threshold.",
"allowed_paths": [
"IntelliTrader.Trading/Processors/BuyProcessor.cs",
"magda_agent_system/agent_tasks.json"
],
"acceptance": [
"BuyProcessor evaluates signal volatility and postpones buys under excessive market turbulence."
]
}
]
}