Compare commits

..

2 Commits

Author SHA1 Message Date
5532ad2473 Supporto Unraid/Docker nativo, healthcheck e template
- Configurazione Kestrel ottimizzata per ambienti Docker/Unraid: porta 8080 in produzione, HTTPS redirect solo in sviluppo
- Endpoint /health sempre attivo per healthcheck automatici
- Aggiunti file docker-compose.yml e unraid-template.xml per deploy e gestione nativa su Unraid (senza Portainer)
- Nuova guida UNRAID_NATIVE_INSTALL.md per installazione, update e troubleshooting su Unraid
- Logging e appsettings separati per Development/Production
- launchSettings.json aggiornato e semplificato
- Rimosso package Azure Containers Tools dal csproj; aggiunto target MSBuild per push automatico su Gitea Registry dopo publish
- Algoritmo SMA più robusto: filtra dati nulli/invalidi e gestisce casi di dati insufficienti
- Pronto per deploy professionale, aggiornamento e gestione semplificata in ambienti containerizzati
2025-12-17 14:34:52 +01:00
8ee8dc7e71 Refactoring Docker: integrazione con Visual Studio
Rimosse configurazioni e script manuali per Docker, build e documentazione. Riscritto il Dockerfile per supportare il flusso di lavoro Visual Studio/.NET 10 con multi-stage build semplificato. Aggiunte impostazioni di pubblicazione Docker in TradingBot.csproj e nuovo profilo "Docker" in launchSettings.json. Eliminati file di configurazione e script non più necessari; aggiunto Dockerfile.original come riferimento legacy. Ottimizzato il progetto per la pubblicazione tramite strumenti Microsoft.
2025-12-15 15:46:26 +01:00
18 changed files with 626 additions and 452 deletions

View File

@@ -1,44 +0,0 @@
# TradingBot - Docker Environment Variables
# Copia questo file come .env per personalizzare la configurazione Docker
# ==============================================
# DOCKER CONFIGURATION
# ==============================================
# Porta esterna per accesso WebUI
# Modifica se la porta 8080 è già in uso sul tuo sistema
# Default: 8080
EXTERNAL_PORT=8080
# ==============================================
# NOTE IMPORTANTI
# ==============================================
#
# ?? TUTTE LE ALTRE CONFIGURAZIONI DELL'APPLICAZIONE
# SONO GESTIBILI DALL'INTERFACCIA WEB:
#
# - Fuso orario (Timezone)
# - Auto-start del bot
# - Intervallo aggiornamento dati
# - Modalità simulazione
# - Notifiche
# - Log level
# - E tutte le altre impostazioni
#
# Accedi all'interfaccia web su:
# http://localhost:8080 (o la porta configurata)
#
# Vai su ?? Impostazioni per configurare l'applicazione.
#
# Le impostazioni sono salvate automaticamente nel volume Docker
# e persistono tra i restart del container.
#
# ==============================================
# EXAMPLES
# ==============================================
#
# Se la porta 8080 è occupata, usa un'altra:
# EXTERNAL_PORT=8081
#
# Poi accedi su: http://localhost:8081
#

153
TradingBot/.gitignore vendored
View File

@@ -1,153 +0,0 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio cache/options directory
.vs/
# Visual Studio Code
.vscode/
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# ReSharper
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JetBrains Rider
.idea/
*.sln.iml
# NuGet Packages
*.nupkg
*.snupkg
**/packages/*
!**/packages/build/
*.nuget.props
*.nuget.targets
project.lock.json
project.fragment.lock.json
artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
*.trx
*.coverage
*.coveragexml
# Node (if used)
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# OS
.DS_Store
Thumbs.db
Desktop.ini
# Application specific
appsettings.Development.json
appsettings.local.json
*.db
*.sqlite
*.sqlite3
# Docker
.env
.env.local
docker-compose.override.yml
# Logs
logs/
*.log
# Temporary files
*.tmp
*.temp
*.bak
*.swp
*~
# Data directories
data/
Data/
# Local settings
%LocalAppData%/
# Secrets (NEVER COMMIT!)
*.key
*.pem
secrets.json

View File

@@ -1,59 +1,30 @@
# Dockerfile per TradingBot - Multi-stage build ottimizzato # Vedere https://aka.ms/customizecontainer per informazioni su come personalizzare il contenitore di debug e su come Visual Studio usa questo Dockerfile per compilare le immagini per un debug più rapido.
# Stage 1: Build
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
# Copy csproj e restore dipendenze (layer caching) # Questa fase viene usata durante l'esecuzione da Visual Studio in modalità rapida (impostazione predefinita per la configurazione di debug)
COPY ["TradingBot.csproj", "./"] FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
RUN dotnet restore "TradingBot.csproj" USER $APP_UID
# Copy tutto il codice sorgente
COPY . .
# Build in Release mode
RUN dotnet build "TradingBot.csproj" -c Release -o /app/build
# Stage 2: Publish
FROM build AS publish
RUN dotnet publish "TradingBot.csproj" -c Release -o /app/publish /p:UseAppHost=false
# Stage 3: Runtime
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS final
WORKDIR /app WORKDIR /app
# Installa wget per health check (curl non disponibile nell'immagine base)
RUN apt-get update && apt-get install -y wget && rm -rf /var/lib/apt/lists/*
# Crea utente non-root per sicurezza
# Usa UID 1001 invece di 1000 (1000 spesso già in uso nell'immagine base)
RUN groupadd -r -g 1001 tradingbot && \
useradd -r -u 1001 -g tradingbot -m -s /bin/bash tradingbot && \
chown -R tradingbot:tradingbot /app
# Esponi porta
EXPOSE 8080 EXPOSE 8080
EXPOSE 8081
# Copy published app
# Questa fase viene usata per compilare il progetto di servizio
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["TradingBot.csproj", "."]
RUN dotnet restore "./TradingBot.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "./TradingBot.csproj" -c $BUILD_CONFIGURATION -o /app/build
# Questa fase viene usata per pubblicare il progetto di servizio da copiare nella fase finale
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./TradingBot.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
# Questa fase viene usata nell'ambiente di produzione o durante l'esecuzione da Visual Studio in modalità normale (impostazione predefinita quando non si usa la configurazione di debug)
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish . COPY --from=publish /app/publish .
# Crea directory per persistenza dati
RUN mkdir -p /app/data && \
chown -R tradingbot:tradingbot /app/data
# Volume per dati persistenti
VOLUME ["/app/data"]
# Switch a utente non-root
USER tradingbot
# Environment variables
ENV ASPNETCORE_URLS=http://+:8080
ENV ASPNETCORE_ENVIRONMENT=Production
ENV DOTNET_RUNNING_IN_CONTAINER=true
# Health check con wget invece di curl
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
# Entry point
ENTRYPOINT ["dotnet", "TradingBot.dll"] ENTRYPOINT ["dotnet", "TradingBot.dll"]

View File

@@ -0,0 +1,59 @@
# Dockerfile per TradingBot - Multi-stage build ottimizzato
# Stage 1: Build
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
# Copy csproj e restore dipendenze (layer caching)
COPY ["TradingBot.csproj", "./"]
RUN dotnet restore "TradingBot.csproj"
# Copy tutto il codice sorgente
COPY . .
# Build in Release mode
RUN dotnet build "TradingBot.csproj" -c Release -o /app/build
# Stage 2: Publish
FROM build AS publish
RUN dotnet publish "TradingBot.csproj" -c Release -o /app/publish /p:UseAppHost=false
# Stage 3: Runtime
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS final
WORKDIR /app
# Installa wget per health check (curl non disponibile nell'immagine base)
RUN apt-get update && apt-get install -y wget && rm -rf /var/lib/apt/lists/*
# Crea utente non-root per sicurezza
# Usa UID 1001 invece di 1000 (1000 spesso già in uso nell'immagine base)
RUN groupadd -r -g 1001 tradingbot && \
useradd -r -u 1001 -g tradingbot -m -s /bin/bash tradingbot && \
chown -R tradingbot:tradingbot /app
# Esponi porta
EXPOSE 8080
# Copy published app
COPY --from=publish /app/publish .
# Crea directory per persistenza dati
RUN mkdir -p /app/data && \
chown -R tradingbot:tradingbot /app/data
# Volume per dati persistenti
VOLUME ["/app/data"]
# Switch a utente non-root
USER tradingbot
# Environment variables
ENV ASPNETCORE_URLS=http://+:8080
ENV ASPNETCORE_ENVIRONMENT=Production
ENV DOTNET_RUNNING_IN_CONTAINER=true
# Health check con wget invece di curl
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
# Entry point
ENTRYPOINT ["dotnet", "TradingBot.dll"]

View File

@@ -3,12 +3,15 @@ using TradingBot.Services;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
// Configure Kestrel per Docker - Listen su tutte le interfacce // Configure Kestrel - Solo in Development usa porte da launchSettings
builder.WebHost.ConfigureKestrel(serverOptions => // In Production/Docker usa porta 8080 su tutte le interfacce
if (builder.Environment.IsProduction() || builder.Environment.EnvironmentName == "Docker")
{ {
// Listen su porta 8080 per Docker builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ListenAnyIP(8080); serverOptions.ListenAnyIP(8080);
}); });
}
// Add services to the container. // Add services to the container.
builder.Services.AddRazorComponents() builder.Services.AddRazorComponents()
@@ -29,12 +32,10 @@ var app = builder.Build();
if (!app.Environment.IsDevelopment()) if (!app.Environment.IsDevelopment())
{ {
app.UseExceptionHandler("/Error", createScopeForErrors: true); app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts(); app.UseHsts();
} }
// Disabilita HTTPS redirect in Docker/Production // HTTPS redirect solo in Development
// Docker gestisce HTTPS tramite reverse proxy se necessario
if (app.Environment.IsDevelopment()) if (app.Environment.IsDevelopment())
{ {
app.UseHttpsRedirection(); app.UseHttpsRedirection();
@@ -43,7 +44,7 @@ if (app.Environment.IsDevelopment())
app.UseStaticFiles(); app.UseStaticFiles();
app.UseAntiforgery(); app.UseAntiforgery();
// Health check endpoint for Docker // Health check endpoint
app.MapHealthChecks("/health"); app.MapHealthChecks("/health");
app.MapRazorComponents<App>() app.MapRazorComponents<App>()

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "https://json.schemastore.org/launchsettings.json", "$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": { "profiles": {
"http": { "TradingBot": {
"commandName": "Project", "commandName": "Project",
"dotnetRunMessages": true, "dotnetRunMessages": true,
"launchBrowser": true, "launchBrowser": true,
@@ -10,7 +10,7 @@
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} }
}, },
"https": { "TradingBot (HTTPS)": {
"commandName": "Project", "commandName": "Project",
"dotnetRunMessages": true, "dotnetRunMessages": true,
"launchBrowser": true, "launchBrowser": true,
@@ -18,6 +18,17 @@
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} }
},
"Docker": {
"commandName": "Docker",
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
"environmentVariables": {
"ASPNETCORE_URLS": "http://+:8080",
"ASPNETCORE_ENVIRONMENT": "Production"
},
"publishAllPorts": true,
"useSSL": false
} }
} }
} }

View File

@@ -11,19 +11,38 @@ public class SimpleMovingAverageStrategy : ITradingStrategy
public Task<TradingSignal> AnalyzeAsync(string symbol, List<MarketPrice> historicalPrices) public Task<TradingSignal> AnalyzeAsync(string symbol, List<MarketPrice> historicalPrices)
{ {
if (historicalPrices.Count < _longPeriod) // Filtra null e valori invalidi prima di usare la lista
if (historicalPrices == null || historicalPrices.Count < _longPeriod)
{ {
return Task.FromResult(new TradingSignal return Task.FromResult(new TradingSignal
{ {
Symbol = symbol, Symbol = symbol,
Type = SignalType.Hold, Type = SignalType.Hold,
Price = historicalPrices.LastOrDefault()?.Price ?? 0, Price = historicalPrices?.LastOrDefault()?.Price ?? 0,
Reason = "Dati insufficienti per l'analisi", Reason = "Dati insufficienti per l'analisi",
Timestamp = DateTime.UtcNow Timestamp = DateTime.UtcNow
}); });
} }
var recentPrices = historicalPrices.OrderByDescending(p => p.Timestamp).Take(_longPeriod).ToList(); // Filtra oggetti null e ordina
var recentPrices = historicalPrices
.Where(p => p != null && p.Price > 0)
.OrderByDescending(p => p.Timestamp)
.Take(_longPeriod)
.ToList();
// Verifica ancora la count dopo il filtro
if (recentPrices.Count < _longPeriod)
{
return Task.FromResult(new TradingSignal
{
Symbol = symbol,
Type = SignalType.Hold,
Price = recentPrices.LastOrDefault()?.Price ?? 0,
Reason = "Dati insufficienti per l'analisi dopo il filtro",
Timestamp = DateTime.UtcNow
});
}
var shortSMA = recentPrices.Take(_shortPeriod).Average(p => p.Price); var shortSMA = recentPrices.Take(_shortPeriod).Average(p => p.Price);
var longSMA = recentPrices.Average(p => p.Price); var longSMA = recentPrices.Average(p => p.Price);

View File

@@ -5,6 +5,44 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<BlazorDisableThrowNavigationException>true</BlazorDisableThrowNavigationException> <BlazorDisableThrowNavigationException>true</BlazorDisableThrowNavigationException>
<!-- Docker Publishing -->
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>.</DockerfileContext>
<!-- Auto-versioning -->
<Version>1.0.0</Version>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion>
</PropertyGroup> </PropertyGroup>
<!-- Post-Publish: Push to Gitea Registry -->
<Target Name="PushToGitea" AfterTargets="Publish" Condition="'$(Configuration)' == 'Release'">
<Message Importance="high" Text="?? Pushing to Gitea Container Registry..." />
<!-- Tag with 'latest' -->
<Exec Command="docker tag tradingbot:latest gitea.encke-hake.ts.net/alby96/encelado/tradingbot:latest"
ContinueOnError="true"
IgnoreExitCode="false" />
<!-- Tag with version -->
<Exec Command="docker tag tradingbot:latest gitea.encke-hake.ts.net/alby96/encelado/tradingbot:$(Version)"
ContinueOnError="true"
IgnoreExitCode="false" />
<!-- Push 'latest' -->
<Exec Command="docker push gitea.encke-hake.ts.net/alby96/encelado/tradingbot:latest"
ContinueOnError="true"
IgnoreExitCode="false" />
<!-- Push versioned -->
<Exec Command="docker push gitea.encke-hake.ts.net/alby96/encelado/tradingbot:$(Version)"
ContinueOnError="true"
IgnoreExitCode="false" />
<Message Importance="high" Text="? Image pushed to Gitea Registry!" />
<Message Importance="high" Text=" - gitea.encke-hake.ts.net/alby96/encelado/tradingbot:latest" />
<Message Importance="high" Text=" - gitea.encke-hake.ts.net/alby96/encelado/tradingbot:$(Version)" />
</Target>
</Project> </Project>

View File

@@ -2,7 +2,7 @@
"Logging": { "Logging": {
"LogLevel": { "LogLevel": {
"Default": "Information", "Default": "Information",
"Microsoft.AspNetCore": "Warning" "Microsoft.AspNetCore": "Information"
} }
} }
} }

View File

@@ -1,20 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://0.0.0.0:8080"
}
},
"Limits": {
"MaxRequestBodySize": 10485760
}
}
}

View File

@@ -5,12 +5,5 @@
"Microsoft.AspNetCore": "Warning" "Microsoft.AspNetCore": "Warning"
} }
}, },
"AllowedHosts": "*", "AllowedHosts": "*"
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://0.0.0.0:8080"
}
}
}
} }

View File

@@ -1,29 +0,0 @@
@echo off
REM Script di build Docker per Windows
echo Building TradingBot Docker Image...
SET IMAGE_NAME=tradingbot
SET TAG=%1
IF "%TAG%"=="" SET TAG=latest
echo Building image: %IMAGE_NAME%:%TAG%
docker build -t %IMAGE_NAME%:%TAG% -f Dockerfile .
IF %ERRORLEVEL% NEQ 0 (
echo Build failed!
exit /b %ERRORLEVEL%
)
echo Build completed successfully!
REM Tag come latest se diverso
IF NOT "%TAG%"=="latest" (
echo Tagging as latest...
docker tag %IMAGE_NAME%:%TAG% %IMAGE_NAME%:latest
)
echo Done! Run with: docker-compose up -d
pause

View File

@@ -1,49 +0,0 @@
#!/bin/bash
# Script di build Docker per TradingBot
set -e
echo "?? Building TradingBot Docker Image..."
# Colori per output
GREEN='\033[0;32m'
BLUE='\033[0;34m'
RED='\033[0;31m'
NC='\033[0m' # No Color
# Variabili
IMAGE_NAME="tradingbot"
TAG="${1:-latest}"
REGISTRY="${DOCKER_REGISTRY:-}" # Opzionale: tuo registry privato
echo -e "${BLUE}?? Building image: ${IMAGE_NAME}:${TAG}${NC}"
# Build dell'immagine
docker build \
--build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
--build-arg VCS_REF=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown") \
-t ${IMAGE_NAME}:${TAG} \
-f Dockerfile \
.
echo -e "${GREEN}? Build completato con successo!${NC}"
# Tag con latest
if [ "$TAG" != "latest" ]; then
echo -e "${BLUE}??? Tagging as latest...${NC}"
docker tag ${IMAGE_NAME}:${TAG} ${IMAGE_NAME}:latest
fi
# Mostra info immagine
echo -e "${BLUE}?? Image info:${NC}"
docker images | grep ${IMAGE_NAME} | head -n 2
# Se registry è configurato, push
if [ ! -z "$REGISTRY" ]; then
echo -e "${BLUE}?? Pushing to registry: ${REGISTRY}${NC}"
docker tag ${IMAGE_NAME}:${TAG} ${REGISTRY}/${IMAGE_NAME}:${TAG}
docker push ${REGISTRY}/${IMAGE_NAME}:${TAG}
echo -e "${GREEN}? Pushed to registry!${NC}"
fi
echo -e "${GREEN}?? Done! Run with: docker-compose up -d${NC}"

View File

@@ -3,17 +3,12 @@ version: '3.8'
services: services:
tradingbot: tradingbot:
container_name: tradingbot container_name: tradingbot
image: tradingbot:latest image: gitea.encke-hake.ts.net/alby96/encelado/tradingbot:latest
build:
context: .
dockerfile: Dockerfile
ports: ports:
- "${EXTERNAL_PORT:-8080}:8080" - "${EXTERNAL_PORT:-8080}:8080"
volumes: volumes:
# Persistenza dati applicazione
- tradingbot-data:/app/data - tradingbot-data:/app/data
environment: environment:
# Configurazioni base (non modificabili)
- ASPNETCORE_ENVIRONMENT=Production - ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://+:8080 - ASPNETCORE_URLS=http://+:8080
restart: unless-stopped restart: unless-stopped

View File

@@ -0,0 +1,427 @@
# ?? TradingBot - Installazione su Unraid (Senza Portainer)
## ? Installazione Diretta da Gitea Registry
Puoi installare TradingBot direttamente dall'Unraid Docker Manager usando il tuo Gitea Registry!
---
## ?? PREREQUISITI
### 1. Login Gitea Registry su Unraid
SSH su Unraid:
```bash
ssh root@192.168.30.23 # O IP Tailscale
# Login al Gitea Registry
docker login gitea.encke-hake.ts.net
# Username: Alby96
# Password: [Personal Access Token Gitea]
```
**Output atteso**:
```
Login Succeeded ?
```
---
## ?? METODO 1: Template XML (Consigliato)
### Step 1: Copia Template su Unraid
```bash
# Su Unraid
mkdir -p /boot/config/plugins/dockerMan/templates-user
# Scarica template
wget -O /boot/config/plugins/dockerMan/templates-user/TradingBot.xml \
https://gitea.encke-hake.ts.net/Alby96/Encelado/raw/branch/main/TradingBot/unraid-template.xml
```
### Step 2: Installa Container
1. Unraid WebUI ? **Docker** tab
2. Click **Add Container** (in fondo)
3. **Template**: Dropdown ? Seleziona **TradingBot**
4. Configura (opzionale):
- **Port**: `8080` (o cambia se occupata)
- **Data Path**: `/mnt/user/appdata/tradingbot/data`
5. Click **Apply**
Unraid farà:
- ? Pull immagine da Gitea Registry
- ? Crea container
- ? Crea volume per dati
- ? Start automatico
### Step 3: Accedi WebUI
```
http://192.168.30.23:8080
```
Dovresti vedere la Dashboard TradingBot! ??
---
## ?? METODO 2: Installazione Manuale
Se preferisci non usare template:
### Step 1: Unraid Docker Tab
1. **Docker** ? **Add Container**
2. **Name**: `TradingBot`
### Step 2: Configurazione Base
**Repository**:
```
gitea.encke-hake.ts.net/alby96/encelado/tradingbot:latest
```
**Network Type**: `Bridge`
**Console shell command**: `Shell`
### Step 3: Port Mapping
Click **Add another Path, Port, Variable, Label or Device**
**Config Type**: `Port`
- **Name**: WebUI
- **Container Port**: `8080`
- **Host Port**: `8080` (o altra porta libera)
- **Connection Type**: `TCP`
### Step 4: Volume Mapping
Click **Add another Path, Port, Variable, Label or Device**
**Config Type**: `Path`
- **Name**: AppData
- **Container Path**: `/app/data`
- **Host Path**: `/mnt/user/appdata/tradingbot/data`
- **Access Mode**: `Read/Write`
### Step 5: Environment Variables
**ASPNETCORE_ENVIRONMENT**:
- **Name**: `ASPNETCORE_ENVIRONMENT`
- **Value**: `Production`
**ASPNETCORE_URLS**:
- **Name**: `ASPNETCORE_URLS`
- **Value**: `http://+:8080`
### Step 6: Health Check (Opzionale)
**Extra Parameters**:
```
--health-cmd="wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1" --health-interval=30s --health-timeout=3s --health-retries=3 --health-start-period=10s
```
### Step 7: Apply
Click **Apply** in fondo alla pagina.
---
## ?? AGGIORNAMENTO CONTAINER
### Via Unraid Docker Tab
1. **Docker** ? Trova **TradingBot**
2. Click **icona ferma** (stop container)
3. Click **Force Update** (icona update)
4. Click **icona play** (start container)
Unraid farà:
- ? Pull ultima immagine da Gitea
- ? Ricrea container
- ? Mantiene dati (volume persistente)
### Automatico con User Scripts Plugin
Installa **User Scripts** plugin:
1. **Apps** ? Cerca "User Scripts"
2. Installa
Crea script update:
```bash
#!/bin/bash
# Nome: Update TradingBot
# Stop container
docker stop TradingBot
# Remove container
docker rm TradingBot
# Pull latest image
docker pull gitea.encke-hake.ts.net/alby96/encelado/tradingbot:latest
# Recreate container (Unraid fa automaticamente)
# O riavvia manualmente dalla WebUI
echo "Update completato! Riavvia TradingBot dalla Docker tab."
```
Schedula: Ogni settimana o manualmente.
---
## ?? GESTIONE CONTAINER
### Start/Stop/Restart
**Docker tab** ? Container **TradingBot**:
- ?? **Play**: Start
- ?? **Pause**: Pausa (mantiene in memoria)
- ?? **Stop**: Ferma
- ?? **Restart**: Riavvia
### View Logs
**Docker tab** ? Container **TradingBot** ? Click **icona logs**
O via terminal:
```bash
docker logs TradingBot -f
```
### Console Access
**Docker tab** ? Container **TradingBot** ? Click **icona console**
O via terminal:
```bash
docker exec -it TradingBot bash
```
### Statistics
**Docker tab** ? Container **TradingBot** ? Click **icona stats**
Mostra:
- CPU usage
- Memory usage
- Network I/O
- Block I/O
---
## ?? ACCESSO WEBUI
### Locale (Unraid LAN)
```
http://192.168.30.23:8080
```
### Via Tailscale
```
http://unraid.encke-hake.ts.net:8080
```
(Se hai configurato Tailscale su Unraid)
### Reverse Proxy (Opzionale)
Se vuoi accesso HTTPS:
**Nginx Proxy Manager** (tramite Unraid):
```
https://tradingbot.encke-hake.ts.net ? http://192.168.30.23:8080
```
---
## ?? SICUREZZA
### Best Practices
? **Porta non esposta pubblicamente** (solo LAN o Tailscale)
? **Volume dati protetto** (`/mnt/user/appdata/tradingbot/`)
? **Registry privato** (Gitea richiede login)
? **Certificati validi** (Tailscale)
? **User non-root** (già configurato nel Dockerfile)
### Backup Dati
```bash
# Backup manuale
tar -czf tradingbot-backup-$(date +%Y%m%d).tar.gz \
/mnt/user/appdata/tradingbot/data
# Restore
tar -xzf tradingbot-backup-20241212.tar.gz -C /
```
O usa **CA Backup / Restore Appdata** plugin.
---
## ?? TROUBLESHOOTING
### Container Non Si Avvia
**Check logs**:
```bash
docker logs TradingBot
```
**Problemi comuni**:
#### Porta occupata
```
Error: address already in use
```
**Fix**: Cambia porta in configurazione container
#### Pull failed
```
Error: unauthorized: authentication required
```
**Fix**: `docker login gitea.encke-hake.ts.net`
#### Image not found
```
Error: manifest not found
```
**Fix**: Verifica che l'immagine esista su Gitea Packages
### WebUI Non Accessibile
**Checklist**:
- [ ] Container status: **running** (verde)
- [ ] Health check: **healthy**
- [ ] Porta corretta (8080 o custom)
- [ ] Firewall Unraid non blocca
- [ ] Browser su `http://` non `https://`
**Test**:
```bash
curl http://localhost:8080/health
# Deve rispondere: Healthy
```
### Performance Issues
**Check risorse**:
```bash
docker stats TradingBot
```
**Limiti raccomandati**:
- **CPU**: 2 cores max, 0.5 reserved
- **Memory**: 1GB max, 256MB reserved
Configura in **Extra Parameters**:
```
--cpus="2.0" --memory="1g" --memory-reservation="256m"
```
---
## ?? CHECKLIST INSTALLAZIONE
### Pre-Install
- [ ] Unraid aggiornato
- [ ] Docker service attivo
- [ ] Porta 8080 disponibile
- [ ] `docker login gitea.encke-hake.ts.net` successful
### Install
- [ ] Template XML copiato (Metodo 1)
- [ ] O container configurato manualmente (Metodo 2)
- [ ] Container creato
- [ ] Volume dati creato
### Post-Install
- [ ] Container status: running
- [ ] Health check: healthy
- [ ] WebUI accessibile
- [ ] Settings configurati nell'app
---
## ?? VANTAGGI UNRAID NATIVO
? **Zero dipendenze** (no Portainer, no docker-compose)
? **WebUI Unraid integrata** (gestione familiare)
? **Auto-start** (container parte con Unraid)
? **Backup integrato** (con plugin CA)
? **Update semplice** (1 click)
? **Template riutilizzabile** (facile reinstall)
---
## ?? WORKFLOW COMPLETO
### Sviluppo (PC)
```
1. Codice in Visual Studio
2. Build ? Publish (Release)
3. ? Automatico: Push Gitea Registry
4. Commit: git push
```
### Deploy (Unraid)
```
1. Docker tab ? TradingBot ? Stop
2. Force Update
3. Start
4. Done! ?
```
**Tempo totale**: ~2 minuti
---
## ?? RISORSE
### Template XML
```
https://gitea.encke-hake.ts.net/Alby96/Encelado/raw/branch/main/TradingBot/unraid-template.xml
```
### Repository
```
https://gitea.encke-hake.ts.net/Alby96/Encelado
```
### Docker Image
```
gitea.encke-hake.ts.net/alby96/encelado/tradingbot:latest
```
### Support
```
https://gitea.encke-hake.ts.net/Alby96/Encelado/issues
```
---
**?? TradingBot pronto per Unraid senza Portainer!**
**Quick Start**:
```bash
# 1. Login
docker login gitea.encke-hake.ts.net
# 2. Install Template
wget -O /boot/config/plugins/dockerMan/templates-user/TradingBot.xml \
https://gitea.encke-hake.ts.net/Alby96/Encelado/raw/branch/main/TradingBot/unraid-template.xml
# 3. Docker tab ? Add Container ? TradingBot ? Apply
```
**Access**: `http://192.168.30.23:8080` ??

View File

@@ -1,43 +0,0 @@
# ?? Documentation Organization Script
# Run this script to organize all documentation files
$docs = "docs"
# Create directory structure
$directories = @(
"installation",
"architecture",
"deployment",
"configuration",
"trading",
"development",
"troubleshooting",
"verification",
"api"
)
foreach ($dir in $directories) {
New-Item -ItemType Directory -Force -Path "$docs\$dir"
}
# Move files to appropriate directories
Write-Host "Moving documentation files..."
# Deployment docs
Move-Item -Path "DOCKER_QUICKSTART.md" -Destination "$docs\deployment\" -Force
Move-Item -Path "UNRAID_DEPLOYMENT.md" -Destination "$docs\deployment\" -Force
Move-Item -Path "DOCKER_BUILD_TEST.md" -Destination "$docs\deployment\" -Force
# Development docs
Move-Item -Path "GIT_WORKFLOW.md" -Destination "$docs\development\" -Force
Move-Item -Path "COMMIT_CHECKLIST.md" -Destination "$docs\development\" -Force
# Troubleshooting docs
Move-Item -Path "BROWSER_CACHE_GUIDE.md" -Destination "$docs\troubleshooting\" -Force
Move-Item -Path "SIDEBAR_TOGGLE_DEBUG.md" -Destination "$docs\troubleshooting\" -Force
# Verification docs
Move-Item -Path "FINAL_VERIFICATION.md" -Destination "$docs\verification\" -Force
Write-Host "? Documentation organized!"
Write-Host "See docs/README.md for index"

View File

@@ -1,31 +0,0 @@
#!/bin/bash
# Documentation Organization Script
# Run this to organize all documentation files
DOCS="docs"
# Create directory structure
echo "Creating directory structure..."
mkdir -p "$DOCS"/{installation,architecture,deployment,configuration,trading,development,troubleshooting,verification,api}
# Move files to appropriate directories
echo "Moving documentation files..."
# Deployment docs
mv DOCKER_QUICKSTART.md "$DOCS/deployment/" 2>/dev/null
mv UNRAID_DEPLOYMENT.md "$DOCS/deployment/" 2>/dev/null
mv DOCKER_BUILD_TEST.md "$DOCS/deployment/" 2>/dev/null
# Development docs
mv GIT_WORKFLOW.md "$DOCS/development/" 2>/dev/null
mv COMMIT_CHECKLIST.md "$DOCS/development/" 2>/dev/null
# Troubleshooting docs
mv BROWSER_CACHE_GUIDE.md "$DOCS/troubleshooting/" 2>/dev/null
mv SIDEBAR_TOGGLE_DEBUG.md "$DOCS/troubleshooting/" 2>/dev/null
# Verification docs
mv FINAL_VERIFICATION.md "$DOCS/verification/" 2>/dev/null
echo "? Documentation organized!"
echo "See docs/README.md for index"

View File

@@ -0,0 +1,29 @@
<?xml version="1.0"?>
<Container version="2">
<Name>TradingBot</Name>
<Repository>gitea.encke-hake.ts.net/alby96/encelado/tradingbot:latest</Repository>
<Registry>https://gitea.encke-hake.ts.net</Registry>
<Network>bridge</Network>
<MyIP/>
<Shell>sh</Shell>
<Privileged>false</Privileged>
<Support>https://gitea.encke-hake.ts.net/Alby96/Encelado</Support>
<Project>https://gitea.encke-hake.ts.net/Alby96/Encelado</Project>
<Overview>Automated Crypto Trading Bot con Blazor UI. Analisi tecnica, simulazione trading e gestione portfolio automatizzata.</Overview>
<Category>Tools:Productivity Status:Stable</Category>
<WebUI>http://[IP]:[PORT:8080]</WebUI>
<TemplateURL>https://gitea.encke-hake.ts.net/Alby96/Encelado/raw/branch/main/TradingBot/unraid-template.xml</TemplateURL>
<Icon>https://raw.githubusercontent.com/docker-library/docs/master/dotnet/logo.png</Icon>
<ExtraParams>--health-cmd="wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1" --health-interval=30s --health-timeout=3s --health-retries=3 --health-start-period=10s</ExtraParams>
<PostArgs/>
<CPUset/>
<DateInstalled/>
<DonateText/>
<DonateLink/>
<Requires/>
<Config Name="WebUI Port" Target="8080" Default="8080" Mode="tcp" Description="Porta per accesso WebUI" Type="Port" Display="always" Required="true" Mask="false">8080</Config>
<Config Name="Data Volume" Target="/app/data" Default="/mnt/user/appdata/tradingbot/data" Mode="rw" Description="Persistenza dati applicazione (impostazioni, trade history)" Type="Path" Display="always" Required="true" Mask="false">/mnt/user/appdata/tradingbot/data</Config>
<Config Name="ASPNETCORE_ENVIRONMENT" Target="ASPNETCORE_ENVIRONMENT" Default="Production" Mode="" Description="Ambiente ASP.NET Core (non modificare)" Type="Variable" Display="advanced" Required="false" Mask="false">Production</Config>
<Config Name="ASPNETCORE_URLS" Target="ASPNETCORE_URLS" Default="http://+:8080" Mode="" Description="URL binding (non modificare)" Type="Variable" Display="advanced" Required="false" Mask="false">http://+:8080</Config>
<Config Name="DOTNET_RUNNING_IN_CONTAINER" Target="DOTNET_RUNNING_IN_CONTAINER" Default="true" Mode="" Description=".NET container flag (non modificare)" Type="Variable" Display="advanced" Required="false" Mask="false">true</Config>
</Container>