Initial commit: IBKRTrader

.NET WinForms-Anwendung (Core, Modules/CongressTrading, UI).
Enthaelt .gitignore und settings.example.json als Konfigurationsvorlage.
Echte settings.json mit Zugangsdaten ist bewusst ausgeschlossen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-07-26 18:19:47 +02:00
co-authored by Claude Opus 4.8
commit ebeb035e92
47 changed files with 4527 additions and 0 deletions
@@ -0,0 +1,79 @@
using IBKRTrader.Core.Logging;
namespace IBKRTrader.Core.Database.Migrations;
/// <summary>
/// Erstellt alle core_xxx-Tabellen idempotent (IF NOT EXISTS).
/// Wird einmalig beim App-Start ausgeführt.
/// </summary>
public class CoreMigrations
{
private readonly DatabaseService _db;
private readonly LoggingService _logger;
public CoreMigrations(DatabaseService db, LoggingService logger)
{
_db = db;
_logger = logger;
}
public async Task RunAsync()
{
_logger.Info("Core", "Starte Core-Datenbankmigrationen...");
await CreateCoreSettingsAsync();
await CreateCoreWorkerLogAsync();
await CreateCoreTradeHistoryAsync();
await CreateCoreBudgetAsync();
_logger.Info("Core", "Core-Migrationen abgeschlossen.");
}
// ─── Tabellen ─────────────────────────────────────────────────────────────
private Task CreateCoreSettingsAsync() => _db.ExecuteAsync(@"
CREATE TABLE IF NOT EXISTS `core_settings` (
`key` VARCHAR(100) NOT NULL PRIMARY KEY,
`value` TEXT,
`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
private Task CreateCoreWorkerLogAsync() => _db.ExecuteAsync(@"
CREATE TABLE IF NOT EXISTS `core_worker_log` (
`id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`worker_name` VARCHAR(100) NOT NULL,
`module` VARCHAR(50) NOT NULL DEFAULT 'Core',
`started_at` DATETIME,
`finished_at` DATETIME,
`status` ENUM('Running','Success','Error') DEFAULT 'Running',
`message` TEXT,
INDEX `idx_worker` (`worker_name`, `started_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
private Task CreateCoreTradeHistoryAsync() => _db.ExecuteAsync(@"
CREATE TABLE IF NOT EXISTS `core_trade_history` (
`id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`module` VARCHAR(50) NOT NULL,
`symbol` VARCHAR(20) NOT NULL,
`action` ENUM('BUY','SELL') NOT NULL,
`quantity` DECIMAL(18,4),
`price` DECIMAL(18,4),
`total_value` DECIMAL(18,4),
`traded_at` DATETIME,
`ibkr_order_id` VARCHAR(100),
`status` VARCHAR(50),
`notes` TEXT,
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX `idx_symbol` (`symbol`),
INDEX `idx_module` (`module`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
private Task CreateCoreBudgetAsync() => _db.ExecuteAsync(@"
CREATE TABLE IF NOT EXISTS `core_budget` (
`module` VARCHAR(50) NOT NULL PRIMARY KEY,
`total_budget` DECIMAL(18,2) DEFAULT 0,
`used_budget` DECIMAL(18,2) DEFAULT 0,
`max_per_trade` DECIMAL(18,2) DEFAULT 0,
`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
}
@@ -0,0 +1,85 @@
using IBKRTrader.Core.Logging;
namespace IBKRTrader.Core.Database.Migrations;
/// <summary>
/// Erstellt die core_ibkr_xxx-Tabellen idempotent (IF NOT EXISTS).
/// Wird beim App-Start nach CoreMigrations ausgeführt.
/// </summary>
public class IBKRMigrations
{
private readonly DatabaseService _db;
private readonly LoggingService _logger;
public IBKRMigrations(DatabaseService db, LoggingService logger)
{
_db = db;
_logger = logger;
}
public async Task RunAsync()
{
_logger.Info("Core", "Starte IBKR-Datenbankmigrationen...");
await CreateInstrumentsTableAsync();
await CreateMarketDataTableAsync();
await CreateExternalIdentifiersTableAsync();
_logger.Info("Core", "IBKR-Migrationen abgeschlossen.");
}
// ─── Tabellen ─────────────────────────────────────────────────────────────
private Task CreateInstrumentsTableAsync() => _db.ExecuteAsync(@"
CREATE TABLE IF NOT EXISTS `core_ibkr_instruments` (
`id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`ibkr_conid` BIGINT NOT NULL UNIQUE,
`symbol` VARCHAR(20) NOT NULL,
`sec_type` VARCHAR(10) NOT NULL DEFAULT 'STK',
`exchange` VARCHAR(20) NOT NULL DEFAULT 'SMART',
`primary_exchange` VARCHAR(20),
`currency` VARCHAR(5) NOT NULL DEFAULT 'USD',
`company_name` TEXT,
`isin` VARCHAR(12),
`sector` VARCHAR(100),
`industry` VARCHAR(100),
`description` TEXT,
`active` TINYINT(1) NOT NULL DEFAULT 1,
`last_fetched` DATETIME,
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP,
INDEX `idx_symbol` (`symbol`),
INDEX `idx_conid` (`ibkr_conid`),
INDEX `idx_active` (`active`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
private Task CreateMarketDataTableAsync() => _db.ExecuteAsync(@"
CREATE TABLE IF NOT EXISTS `core_ibkr_market_data` (
`instrument_id` BIGINT NOT NULL,
`bar_size` VARCHAR(10) NOT NULL DEFAULT 'daily',
`timestamp` DATETIME NOT NULL,
`open` DECIMAL(12,6),
`high` DECIMAL(12,6),
`low` DECIMAL(12,6),
`close` DECIMAL(12,6),
`volume` BIGINT,
`wap` DECIMAL(12,6),
`bar_count` INT,
PRIMARY KEY (`instrument_id`, `bar_size`, `timestamp`),
INDEX `idx_timestamp` (`timestamp`),
CONSTRAINT `fk_md_instrument` FOREIGN KEY (`instrument_id`)
REFERENCES `core_ibkr_instruments` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
private Task CreateExternalIdentifiersTableAsync() => _db.ExecuteAsync(@"
CREATE TABLE IF NOT EXISTS `core_ibkr_external_identifiers` (
`id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`instrument_id` BIGINT NOT NULL,
`source` VARCHAR(50) NOT NULL,
`ticker` VARCHAR(50) NOT NULL,
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY `uq_mapping` (`instrument_id`, `source`, `ticker`),
INDEX `idx_source_ticker` (`source`, `ticker`),
CONSTRAINT `fk_ext_instrument` FOREIGN KEY (`instrument_id`)
REFERENCES `core_ibkr_instruments` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
}