HTML
Börsenlabor Handelsplatz Simulation
Eine Handelssimulation von Aktien mit Bots und mehr
Keine Vorschau vorhanden
Code-Snapshot
Dies ist der veröffentlichte Zustand. Spätere Änderungen am Code überschreiben diese Veröffentlichung nicht automatisch.
[{"text":"Projekt","spriteCssClass":"fa fa-folder","items":[{"text":"index.html","spriteCssClass":"fa fa-file-code-o","code":"<!DOCTYPE html>\n<html lang='de'>\n<head>\n <meta charset='UTF-8'>\n <meta name='viewport' content='width=device-width, initial-scale=1.0'>\n <title>Börsenlabor</title>\n <link rel='stylesheet' href='style.css'>\n</head>\n<body>\n <header class='kopfbereich'>\n <div>\n <p class='label'>CodeRoom AI Project Lab</p>\n <h1>Börsenlabor: Handelsplatz-Simulation</h1>\n <p class='untertitel'>Baue eine simulierte Börse mit Kursen, Nachrichten, Bot-Händlern und deinem eigenen Depot.</p>\n </div>\n <div class='marktkarte'>\n <span id='marktphase'>ruhig</span>\n <strong id='uhr'>09:00</strong>\n </div>\n </header>\n\n <div id='startBildschirm' class='startBildschirm'>\n <div class='startInhalt'>\n <h2>Willkommen im Börsenlabor</h2>\n <p>Dein Ziel: Steigere dein Startkapital von 10.000 € durch klugen Aktienhandel.</p>\n <p>Beobachte die Kurse, reagiere auf Nachrichten und handle, bevor die Bot-Händler den Markt verändern.</p>\n <button id='startKnopf'>Start</button>\n </div>\n </div>\n\n <main class='layout'>\n <section class='bereich panel hero'>\n <div>\n <h2>Dein Handelstag</h2>\n <p>Kaufe und verkaufe Aktien, bevor Bot-Händler und Nachrichten den Markt verändern.</p>\n </div>\n <div class='kennzahlen'>\n <div>\n <span>Barbestand</span>\n <strong id='barbestand'>0 €</strong>\n </div>\n <div>\n <span>Depotwert</span>\n <strong id='depotwert'>0 €</strong>\n </div>\n <div>\n <span>Gesamt</span>\n <strong id='gesamtwert'>0 €</strong>\n </div>\n </div>\n <div class='steuerung'>\n <button id='pauseKnopf'>Pause</button>\n <button id='ereignisKnopf'>Nachricht auslösen</button>\n <button id='resetKnopf'>Neustart</button>\n </div>\n </section>\n\n <section class='bereich panel'>\n <div class='bereichskopf'>\n <h2>Markt</h2>\n <p>Wähle eine Aktie aus und handle eine Einheit.</p>\n </div>\n <div id='aktienListe' class='aktienListe'></div>\n </section>\n\n <section class='bereich panel'>\n <div class='bereichskopf'>\n <h2>Chart</h2>\n <p id='chartTitel'>Wähle eine Aktie.</p>\n </div>\n <canvas id='kursChart' width='720' height='260'></canvas>\n <p class='hinweis'>TODO: Baue später Candlesticks, Zoom oder Zeitachsen ein.</p>\n </section>\n\n <aside class='bereich panel seitenleiste'>\n <div id='watchlist' class='watchlist'></div>\n <h2>Depot</h2>\n <div id='depotListe' class='depotListe'></div>\n <h2>Nachrichtenfeed</h2>\n <div id='nachrichtenListe' class='nachrichtenListe'></div>\n <h2>Bot-Händler</h2>\n <div id='botListe' class='botListe'></div>\n </aside>\n </main>\n\n <script src='script.js'></script>\n</body>\n</html>","isMain":true},{"text":"script.js","spriteCssClass":"fa fa-file-code-o","code":"const startBarbestand = 10000;\nlet barbestand = startBarbestand;\nlet pausiert = true;\nlet minuten = 9 * 60;\nlet ausgewaehlteAktie = 'NEON';\nlet watchlist = [];\n\nconst marktphasen = [\n { name: 'ruhig', bewegung: 0.7, bots: 0.4 },\n { name: 'nervös', bewegung: 1.4, bots: 0.7 },\n { name: 'Boom', bewegung: 1.1, bots: 0.9 },\n { name: 'Crash', bewegung: 2.2, bots: 1.0 },\n { name: 'stabil', bewegung: 0.5, bots: 0.3 },\n { name: 'volatil', bewegung: 1.8, bots: 0.8 },\n { name: 'Hausse', bewegung: 0.9, bots: 0.7 },\n { name: 'Baisse', bewegung: 1.6, bots: 0.9 }\n];\n\nlet aktuellePhase = marktphasen[0];\n\nconst aktien = [\n { symbol: 'NEON', name: 'NeonTech', branche: 'Tech', preis: 86, trend: 0, bestand: 0, verlauf: [86], watched: false, alertPrice: null },\n { symbol: 'SOL', name: 'Solaris Energie', branche: 'Energie', preis: 62, trend: 0, bestand: 0, verlauf: [62], watched: false, alertPrice: null },\n { symbol: 'MEDI', name: 'MedNova', branche: 'Medizin', preis: 104, trend: 0, bestand: 0, verlauf: [104], watched: false, alertPrice: null },\n { symbol: 'PIX', name: 'PixelForge', branche: 'Gaming', preis: 45, trend: 0, bestand: 0, verlauf: [45], watched: false, alertPrice: null },\n { symbol: 'AUTO', name: 'AutoDrive', branche: 'Automobil', preis: 78, trend: 0, bestand: 0, verlauf: [78], watched: false, alertPrice: null },\n { symbol: 'FIN', name: 'FinTech Global', branche: 'Finanzen', preis: 92, trend: 0, bestand: 0, verlauf: [92], watched: false, alertPrice: null },\n { symbol: 'FOOD', name: 'GreenHarvest', branche: 'Nahrung', preis: 55, trend: 0, bestand: 0, verlauf: [55], watched: false, alertPrice: null },\n { symbol: 'REAL', name: 'UrbanSpaces', branche: 'Immobilien', preis: 112, trend: 0, bestand: 0, verlauf: [112], watched: false, alertPrice: null }\n];\n\nconst bots = [\n { name: 'Mira', typ: 'vorsichtig', stimmung: 0.2 },\n { name: 'Kai', typ: 'riskant', stimmung: 0.8 },\n { name: 'RoboRalf', typ: 'panisch', stimmung: 0.5 },\n { name: 'Luna', typ: 'analytisch', stimmung: 0.6 },\n { name: 'Max', typ: 'konservativ', stimmung: 0.3 },\n { name: 'Zoe', typ: 'aggressiv', stimmung: 0.9 },\n { name: 'Tron', typ: 'algorithmic', stimmung: 0.7 }\n];\n\nconst nachrichtenPool = [\n { titel: 'Neue Chiptechnik begeistert Anleger', branche: 'Tech', wirkung: 5 },\n { titel: 'Sturm legt Windparks kurz lahm', branche: 'Energie', wirkung: -4 },\n { titel: 'Studie meldet Durchbruch in Therapie', branche: 'Medizin', wirkung: 6 },\n { titel: 'Gaming-Messe startet mit Rekorden', branche: 'Gaming', wirkung: 4 },\n { titel: 'Gerüchte sorgen für Unsicherheit am Markt', branche: 'alle', wirkung: -3 },\n { titel: 'Elektroauto-Absatz steigt stark an', branche: 'Automobil', wirkung: 7 },\n { titel: 'Zinserhöhung erwartet', branche: 'Finanzen', wirkung: -5 },\n { titel: 'Erntedankfest bringt Rekordumsätze', branche: 'Nahrung', wirkung: 3 },\n { titel: 'Neue Wohnbauprojekte genehmigt', branche: 'Immobilien', wirkung: 4 },\n { titel: 'KI-Entwicklung beschleunigt sich', branche: 'Tech', wirkung: 8 },\n { titel: 'Ölpreis steigt überraschend', branche: 'Energie', wirkung: -2 },\n { titel: 'Neues Medikament zugelassen', branche: 'Medizin', wirkung: 9 },\n { titel: 'E-Sport-Turnier bricht Zuschauerrekord', branche: 'Gaming', wirkung: 5 },\n { titel: 'Wirtschaftswachstum übertrifft Erwartungen', branche: 'alle', wirkung: 6 },\n { titel: 'Lieferkettenprobleme verschärfen sich', branche: 'alle', wirkung: -4 }\n];\n\nlet nachrichten = [\n 'Willkommen im Börsenlabor. Beobachte die Kurse und starte deinen ersten Handel.'\n];\n\nconst aktienListe = document.querySelector('#aktienListe');\nconst depotListe = document.querySelector('#depotListe');\nconst nachrichtenListe = document.querySelector('#nachrichtenListe');\nconst botListe = document.querySelector('#botListe');\nconst barbestandAnzeige = document.querySelector('#barbestand');\nconst depotwertAnzeige = document.querySelector('#depotwert');\nconst gesamtwertAnzeige = document.querySelector('#gesamtwert');\nconst marktphaseAnzeige = document.querySelector('#marktphase');\nconst uhrAnzeige = document.querySelector('#uhr');\nconst chartTitel = document.querySelector('#chartTitel');\nconst canvas = document.querySelector('#kursChart');\nconst ctx = canvas.getContext('2d');\n\ndocument.querySelector('#pauseKnopf').addEventListener('click', pauseUmschalten);\ndocument.querySelector('#ereignisKnopf').addEventListener('click', zufallsNachricht);\ndocument.querySelector('#resetKnopf').addEventListener('click', neuStarten);\n\ndocument.querySelector('#startKnopf').addEventListener('click', () => {\n document.querySelector('#startBildschirm').style.display = 'none';\n pausiert = false;\n document.querySelector('#pauseKnopf').textContent = 'Pause';\n});\n\n\nfunction euro(wert) {\n return Math.round(wert).toLocaleString('de-DE') + ' €';\n}\n\nfunction findeAktie(symbol) {\n return aktien.find(aktie => aktie.symbol === symbol);\n}\n\nfunction zeichneMarkt() {\n aktienListe.textContent = '';\n\n aktien.forEach(aktie => {\n const karte = document.createElement('article');\n karte.className = 'aktienkarte';\n if (aktie.symbol === ausgewaehlteAktie) {\n karte.classList.add('aktiv');\n }\n karte.dataset.symbol = aktie.symbol;\n\n const kopf = document.createElement('div');\n kopf.className = 'aktienkopf';\n\n const titel = document.createElement('div');\n const name = document.createElement('strong');\n name.textContent = aktie.name;\n const meta = document.createElement('div');\n meta.className = 'meta';\n meta.textContent = aktie.branche;\n titel.appendChild(name);\n titel.appendChild(meta);\n\n const symbol = document.createElement('span');\n symbol.className = 'symbol';\n symbol.textContent = aktie.symbol;\n\n kopf.appendChild(titel);\n kopf.appendChild(symbol);\n\n const preis = document.createElement('div');\n preis.className = 'preis';\n preis.textContent = euro(aktie.preis);\n\n const trend = document.createElement('div');\n trend.className = aktie.trend >= 0 ? 'trendPlus' : 'trendMinus';\n trend.textContent = aktie.trend >= 0 ? '+' + aktie.trend.toFixed(2) + '%' : aktie.trend.toFixed(2) + '%';\n\n const aktionen = document.createElement('div');\n aktionen.className = 'aktionen';\n\n const watchButton = document.createElement('button');\n watchButton.textContent = aktie.watched ? 'Entfernen' : 'Merken';\n watchButton.className = 'watch-button';\n watchButton.addEventListener('click', event => {\n event.stopPropagation();\n toggleWatch(aktie.symbol);\n });\n\n const kauf = document.createElement('button');\n kauf.textContent = 'Kaufen';\n kauf.addEventListener('click', event => {\n event.stopPropagation();\n kaufen(aktie.symbol);\n });\n\n const verkauf = document.createElement('button');\n verkauf.textContent = 'Verkaufen';\n verkauf.disabled = aktie.bestand <= 0;\n verkauf.addEventListener('click', event => {\n event.stopPropagation();\n verkaufen(aktie.symbol);\n });\n\n aktionen.appendChild(kauf);\n aktionen.appendChild(verkauf);\n aktionen.appendChild(watchButton);\n\n karte.appendChild(kopf);\n karte.appendChild(preis);\n karte.appendChild(trend);\n karte.appendChild(aktionen);\n\n karte.addEventListener('click', () => {\n ausgewaehlteAktie = aktie.symbol;\n zeichneAlles();\n });\n\n aktienListe.appendChild(karte);\n });\n}\n\nfunction zeichneDepot() {\n depotListe.textContent = '';\n const eigeneAktien = aktien.filter(aktie => aktie.bestand > 0);\n\n if (eigeneAktien.length === 0) {\n const leer = document.createElement('p');\n leer.className = 'leer';\n leer.textContent = 'Noch keine Aktien im Depot.';\n depotListe.appendChild(leer);\n return;\n }\n\n eigeneAktien.forEach(aktie => {\n const eintrag = document.createElement('div');\n eintrag.className = 'depotEintrag';\n const titel = document.createElement('strong');\n titel.textContent = aktie.symbol + ' x ' + aktie.bestand;\n const wert = document.createElement('div');\n wert.className = 'meta';\n wert.textContent = 'Wert: ' + euro(aktie.bestand * aktie.preis);\n \n const kaufpreis = aktie.verlauf[0];\n const aktuellerWert = aktie.preis;\n const gewinnVerlust = (aktuellerWert - kaufpreis) * aktie.bestand;\n const gewinnSpan = document.createElement('div');\n gewinnSpan.className = gewinnVerlust >= 0 ? 'trendPlus' : 'trendMinus';\n gewinnSpan.textContent = gewinnVerlust >= 0 ? '+' + euro(gewinnVerlust) : euro(gewinnVerlust);\n \n eintrag.appendChild(titel);\n eintrag.appendChild(wert);\n eintrag.appendChild(gewinnSpan);\n depotListe.appendChild(eintrag);\n });\n}\n\nfunction zeichneNachrichten() {\n nachrichtenListe.textContent = '';\n nachrichten.slice(0, 5).forEach(text => {\n const meldung = document.createElement('div');\n meldung.className = 'nachricht';\n meldung.textContent = text;\n nachrichtenListe.appendChild(meldung);\n });\n}\n\nfunction zeichneBots() {\n botListe.textContent = '';\n bots.forEach(bot => {\n const eintrag = document.createElement('div');\n eintrag.className = 'bot';\n\n const name = document.createElement('strong');\n name.textContent = bot.name;\n\n const status = document.createElement('span');\n status.className = 'meta';\n status.textContent = bot.typ + ' · Stimmung ' + Math.round(bot.stimmung * 100) + '%';\n\n eintrag.appendChild(name);\n eintrag.appendChild(status);\n botListe.appendChild(eintrag);\n });\n}\nfunction zeichneWatchlist() {\n const watchlistSection = document.querySelector('#watchlist');\n if (!watchlistSection) return;\n \n watchlistSection.innerHTML = '<h2>Watchlist</h2>';\n const watchlistContainer = document.createElement('div');\n watchlistContainer.className = 'watchlist-container';\n \n const watchedStocks = aktien.filter(aktie => aktie.watched);\n \n if (watchedStocks.length === 0) {\n const leer = document.createElement('p');\n leer.className = 'leer';\n leer.textContent = 'Keine Aktien in der Watchlist.';\n watchlistContainer.appendChild(leer);\n } else {\n watchedStocks.forEach(aktie => {\n const eintrag = document.createElement('div');\n eintrag.className = 'watchlist-eintrag';\n \n const titel = document.createElement('strong');\n titel.textContent = aktie.symbol + ' - ' + aktie.name;\n \n const preis = document.createElement('div');\n preis.className = 'preis';\n preis.textContent = euro(aktie.preis);\n \n const alarmInfo = document.createElement('div');\n alarmInfo.className = 'meta';\n alarmInfo.textContent = 'Alarmpreis: ' + euro(aktie.alertPrice);\n \n eintrag.appendChild(titel);\n eintrag.appendChild(preis);\n eintrag.appendChild(alarmInfo);\n watchlistContainer.appendChild(eintrag);\n });\n }\n \n watchlistSection.appendChild(watchlistContainer);\n}\n\n\nfunction zeichneWerte() {\n const depotwert = aktien.reduce((summe, aktie) => summe + aktie.bestand * aktie.preis, 0);\n barbestandAnzeige.textContent = euro(barbestand);\n depotwertAnzeige.textContent = euro(depotwert);\n gesamtwertAnzeige.textContent = euro(barbestand + depotwert);\n marktphaseAnzeige.textContent = aktuellePhase.name;\n const stunde = Math.floor(minuten / 60);\n const minute = minuten % 60;\n uhrAnzeige.textContent = String(stunde).padStart(2, '0') + ':' + String(minute).padStart(2, '0');\n}\n\nfunction zeichneChart() {\n const aktie = findeAktie(ausgewaehlteAktie);\n chartTitel.textContent = aktie.name + ' Kursverlauf';\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n\n const werte = aktie.verlauf;\n const maxWert = Math.max(...werte);\n const minWert = Math.min(...werte);\n const max = maxWert + 5;\n const min = minWert - 5;\n const breite = canvas.width;\n const hoehe = canvas.height;\n\n // Zeichne Gitternetzlinien\n ctx.strokeStyle = '#1e293b';\n ctx.lineWidth = 1;\n for (let i = 0; i < 6; i++) {\n const y = 20 + i * ((hoehe - 40) / 5);\n ctx.beginPath();\n ctx.moveTo(20, y);\n ctx.lineTo(breite - 20, y);\n ctx.stroke();\n }\n\n // Zeichne Kursverlauf\n ctx.strokeStyle = '#7dd3fc';\n ctx.lineWidth = 4;\n ctx.beginPath();\n\n werte.forEach((wert, index) => {\n const x = 20 + index * ((breite - 40) / Math.max(werte.length - 1, 1));\n const y = hoehe - 20 - ((wert - min) / (max - min)) * (hoehe - 40);\n if (index === 0) {\n ctx.moveTo(x, y);\n } else {\n ctx.lineTo(x, y);\n }\n });\n\n ctx.stroke();\n\n // Markiere höchsten und niedrigsten Kurs\n const maxIndex = werte.indexOf(maxWert);\n const minIndex = werte.indexOf(minWert);\n\n // Höchster Kurs\n const maxX = 20 + maxIndex * ((breite - 40) / Math.max(werte.length - 1, 1));\n const maxY = hoehe - 20 - ((maxWert - min) / (max - min)) * (hoehe - 40);\n ctx.fillStyle = '#86efac';\n ctx.beginPath();\n ctx.arc(maxX, maxY, 6, 0, Math.PI * 2);\n ctx.fill();\n\n // Niedrigster Kurs\n const minX = 20 + minIndex * ((breite - 40) / Math.max(werte.length - 1, 1));\n const minY = hoehe - 20 - ((minWert - min) / (max - min)) * (hoehe - 40);\n ctx.fillStyle = '#fca5a5';\n ctx.beginPath();\n ctx.arc(minX, minY, 6, 0, Math.PI * 2);\n ctx.fill();\n\n // Achsenbeschriftungen\n ctx.fillStyle = '#94a3b8';\n ctx.font = '12px Arial';\n ctx.textAlign = 'right';\n ctx.textBaseline = 'middle';\n\n // Y-Achse (Preise)\n for (let i = 0; i <= 5; i++) {\n const preis = max - i * ((max - min) / 5);\n const y = 20 + i * ((hoehe - 40) / 5);\n ctx.fillText(euro(preis), 15, y);\n }\n\n // X-Achse (Zeitpunkte)\n ctx.textAlign = 'center';\n ctx.textBaseline = 'top';\n const anzahlPunkte = Math.min(werte.length, 5);\n for (let i = 0; i < anzahlPunkte; i++) {\n const index = Math.floor(i * (werte.length - 1) / (anzahlPunkte - 1));\n const x = 20 + index * ((breite - 40) / Math.max(werte.length - 1, 1));\n ctx.fillText(index + 1, x, hoehe - 15);\n }\n\n // Legende für Markierungen\n ctx.textAlign = 'left';\n ctx.textBaseline = 'top';\n ctx.fillText('Höchster Kurs', 30, 30);\n ctx.fillStyle = '#86efac';\n ctx.beginPath();\n ctx.arc(25, 25, 4, 0, Math.PI * 2);\n ctx.fill();\n\n ctx.fillStyle = '#94a3b8';\n ctx.fillText('Niedrigster Kurs', 30, 50);\n ctx.fillStyle = '#fca5a5';\n ctx.beginPath();\n ctx.arc(25, 45, 4, 0, Math.PI * 2);\n ctx.fill();\n}\n\nfunction kaufen(symbol) {\n const aktie = findeAktie(symbol);\n if (barbestand >= aktie.preis) {\n barbestand -= aktie.preis;\n aktie.bestand += 1;\n nachrichten.unshift('Du kaufst 1 Aktie von ' + aktie.name + '.');\n zeichneAlles();\n }\n}\n\nfunction verkaufen(symbol) {\n const aktie = findeAktie(symbol);\n if (aktie.bestand > 0) {\n barbestand += aktie.preis;\n aktie.bestand -= 1;\n nachrichten.unshift('Du verkaufst 1 Aktie von ' + aktie.name + '.');\n zeichneAlles();\n }\n}\nfunction toggleWatch(symbol) {\n const aktie = findeAktie(symbol);\n aktie.watched = !aktie.watched;\n \n if (aktie.watched) {\n aktie.alertPrice = aktie.preis * 1.05;\n nachrichten.unshift(aktie.name + ' zur Watchlist hinzugefügt. Alarm bei ' + euro(aktie.alertPrice));\n } else {\n aktie.alertPrice = null;\n nachrichten.unshift(aktie.name + ' aus Watchlist entfernt.');\n }\n \n zeichneAlles();\n}\n\nfunction checkAlerts() {\n aktien.forEach(aktie => {\n if (aktie.watched && aktie.alertPrice && aktie.preis >= aktie.alertPrice) {\n nachrichten.unshift('ALARM: ' + aktie.name + ' hat ' + euro(aktie.alertPrice) + ' erreicht!');\n aktie.watched = false;\n aktie.alertPrice = null;\n }\n });\n}\n\n\nfunction zufallsNachricht() {\n const ereignis = nachrichtenPool[Math.floor(Math.random() * nachrichtenPool.length)];\n nachrichten.unshift(ereignis.titel + ' Wirkung: ' + ereignis.branche + ' ' + ereignis.wirkung + '%');\n\n aktien.forEach(aktie => {\n if (ereignis.branche === 'alle' || aktie.branche === ereignis.branche) {\n aktie.preis *= 1 + ereignis.wirkung / 100;\n aktie.trend += ereignis.wirkung;\n aktie.verlauf.push(aktie.preis);\n begrenzeVerlauf(aktie);\n }\n });\n\n // TODO: Lasse Nachrichten auch die Stimmung der passenden Bot-Händler verändern.\n zeichneAlles();\n}\n\nfunction simuliereSchritt() {\n if (pausiert) {\n return;\n }\n\n minuten += 5;\n if (minuten >= 17 * 60) {\n pausiert = true;\n document.querySelector('#pauseKnopf').textContent = 'Weiter';\n \n const depotwert = aktien.reduce((summe, aktie) => summe + aktie.bestand * aktie.preis, 0);\n const gesamtwert = barbestand + depotwert;\n const gewinnVerlust = gesamtwert - startBarbestand;\n const prozent = (gesamtwert / startBarbestand - 1) * 100;\n \n nachrichten.unshift('BÖRSENENDE: Handelstag beendet. Dein Endstand: ' + euro(gesamtwert) + \n ' (' + (gewinnVerlust >= 0 ? '+' : '') + euro(gewinnVerlust) + \n ', ' + prozent.toFixed(2) + '%).');\n \n return;\n }\n\n if (Math.random() < 0.08) {\n aktuellePhase = marktphasen[Math.floor(Math.random() * marktphasen.length)];\n nachrichten.unshift('Marktphase wechselt zu ' + aktuellePhase.name + '.');\n }\n\n aktien.forEach(aktie => {\n const grundBewegung = (Math.random() - 0.48) * aktuellePhase.bewegung;\n const botDruck = berechneBotDruck(aktie);\n const prozent = grundBewegung + botDruck;\n aktie.trend = prozent;\n aktie.preis = Math.max(3, aktie.preis * (1 + prozent / 100));\n aktie.verlauf.push(aktie.preis);\n begrenzeVerlauf(aktie);\n });\n\n if (Math.random() < 0.18) {\n zufallsNachricht();\n }\n\n checkAlerts();\n zeichneAlles();\n}\n\nfunction berechneBotDruck(aktie) {\n let druck = 0;\n\n bots.forEach(bot => {\n const impuls = (Math.random() - 0.5) * bot.stimmung * aktuellePhase.bots;\n druck += impuls;\n\n if (bot.typ === 'panisch' && aktuellePhase.name === 'Crash') {\n druck -= 0.35;\n }\n\n if (bot.typ === 'riskant' && aktuellePhase.name === 'Boom') {\n druck += 0.25;\n }\n\n // Bot-Händler führen gelegentlich sichtbare Aktionen durch\n if (Math.random() < 0.15) { // 15% Chance auf eine sichtbare Aktion\n let aktion, richtung;\n \n // Entscheidungslogik basierend auf Bot-Typ und Marktphase\n if (bot.typ === 'vorsichtig') {\n if (aktuellePhase.name === 'Boom' && Math.random() < 0.6) {\n aktion = 'verkauft';\n richtung = -0.1;\n } else if (aktuellePhase.name === 'Crash' && Math.random() < 0.7) {\n aktion = 'kauft';\n richtung = 0.1;\n } else {\n aktion = Math.random() < 0.5 ? 'kauft' : 'verkauft';\n richtung = Math.random() < 0.5 ? 0.08 : -0.08;\n }\n } else if (bot.typ === 'riskant') {\n if (aktuellePhase.name === 'Boom') {\n aktion = 'kauft';\n richtung = 0.15;\n } else if (aktuellePhase.name === 'Crash' && Math.random() < 0.3) {\n aktion = 'kauft';\n richtung = 0.2;\n } else {\n aktion = Math.random() < 0.7 ? 'kauft' : 'verkauft';\n richtung = Math.random() < 0.7 ? 0.12 : -0.1;\n }\n } else if (bot.typ === 'panisch') {\n if (aktuellePhase.name === 'Crash') {\n aktion = 'verkauft';\n richtung = -0.2;\n } else if (aktuellePhase.name === 'Boom' && Math.random() < 0.4) {\n aktion = 'verkauft';\n richtung = -0.15;\n } else {\n aktion = Math.random() < 0.3 ? 'kauft' : 'verkauft';\n richtung = Math.random() < 0.3 ? 0.05 : -0.12;\n }\n }\n\n // Nachricht im Feed anzeigen\n nachrichten.unshift(`${bot.name} (${bot.typ}) ${aktion} Aktien von ${aktie.name} (${aktie.symbol}).`);\n \n // Kurs leicht beeinflussen\n druck += richtung;\n }\n });\n\n return druck;\n}\n\nfunction begrenzeVerlauf(aktie) {\n if (aktie.verlauf.length > 40) {\n aktie.verlauf.shift();\n }\n}\n\nfunction pauseUmschalten() {\n pausiert = !pausiert;\n document.querySelector('#pauseKnopf').textContent = pausiert ? 'Weiter' : 'Pause';\n}\n\nfunction neuStarten() {\n barbestand = startBarbestand;\n minuten = 9 * 60;\n aktuellePhase = marktphasen[0];\n nachrichten = ['Neuer Start. Teste eine andere Handelsstrategie.'];\n aktien.forEach(aktie => {\n aktie.bestand = 0;\n aktie.trend = 0;\n aktie.verlauf = [aktie.preis];\n });\n zeichneAlles();\n}\n\nfunction zeichneAlles() {\n zeichneWerte();\n zeichneMarkt();\n zeichneDepot();\n zeichneNachrichten();\n zeichneBots();\n zeichneChart();\n zeichneWatchlist();\n}\n\nzeichneAlles();\nsetInterval(simuliereSchritt, 1800);","isMain":false},{"text":"style.css","spriteCssClass":"fa fa-file-code-o","code":"* {\n box-sizing: border-box;\n}\n\nbody {\n margin: 0;\n font-family: Arial, Helvetica, sans-serif;\n color: #f2f6ff;\n background: radial-gradient(circle at top left, #263b75, #101628 45%, #070a12 100%);\n min-height: 100vh;\n}\n\n.kopfbereich {\n display: flex;\n justify-content: space-between;\n gap: 1rem;\n align-items: center;\n padding: 2rem;\n border-bottom: 1px solid rgba(255,255,255,0.12);\n}\n\n.label {\n text-transform: uppercase;\n letter-spacing: 0.18rem;\n color: #7dd3fc;\n font-size: 0.78rem;\n margin: 0 0 0.4rem;\n}\n\nh1, h2, p {\n margin-top: 0;\n}\n\nh1 {\n font-size: clamp(2rem, 5vw, 4rem);\n margin-bottom: 0.5rem;\n}\n\n.untertitel {\n max-width: 760px;\n color: #cbd5e1;\n line-height: 1.5;\n}\n\n.marktkarte {\n min-width: 150px;\n background: rgba(15, 23, 42, 0.85);\n border: 1px solid rgba(125, 211, 252, 0.35);\n border-radius: 22px;\n padding: 1rem;\n text-align: center;\n box-shadow: 0 20px 50px rgba(0,0,0,0.3);\n}\n\n.marktkarte span {\n display: block;\n color: #93c5fd;\n text-transform: uppercase;\n letter-spacing: 0.12rem;\n font-size: 0.78rem;\n}\n\n.marktkarte strong {\n font-size: 2rem;\n}\n\n.layout {\n display: grid;\n grid-template-columns: 1.4fr 1fr;\n gap: 1rem;\n padding: 1rem;\n}\n\n.bereich {\n min-width: 0;\n}\n\n.panel {\n background: rgba(15, 23, 42, 0.72);\n border: 1px solid rgba(255,255,255,0.12);\n border-radius: 24px;\n padding: 1rem;\n box-shadow: 0 12px 40px rgba(0,0,0,0.22);\n backdrop-filter: blur(14px);\n}\n\n.hero {\n grid-column: 1 / -1;\n display: grid;\n grid-template-columns: 1.2fr 1fr auto;\n gap: 1rem;\n align-items: center;\n}\n\n.kennzahlen {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 0.7rem;\n}\n\n.kennzahlen div,\n.aktienkarte,\n.depotEintrag,\n.nachricht,\n.bot {\n background: rgba(255,255,255,0.07);\n border: 1px solid rgba(255,255,255,0.1);\n border-radius: 18px;\n padding: 0.85rem;\n}\n\n.kennzahlen span,\n.meta {\n color: #94a3b8;\n font-size: 0.82rem;\n}\n\n.kennzahlen strong {\n display: block;\n font-size: 1.25rem;\n margin-top: 0.25rem;\n}\n\n.steuerung {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\nbutton {\n border: 0;\n border-radius: 999px;\n padding: 0.72rem 1rem;\n background: linear-gradient(135deg, #38bdf8, #818cf8);\n color: #06111f;\n font-weight: 700;\n cursor: pointer;\n transition: transform 0.18s, filter 0.18s;\n}\n\nbutton:hover {\n transform: translateY(-2px);\n filter: brightness(1.1);\n}\n\nbutton:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n transform: none;\n}\n\n.bereichskopf {\n display: flex;\n justify-content: space-between;\n gap: 1rem;\n align-items: end;\n}\n\n.aktienListe {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));\n gap: 0.8rem;\n}\n\n.aktienkarte {\n cursor: pointer;\n position: relative;\n overflow: hidden;\n}\n\n.aktienkarte.aktiv {\n outline: 2px solid #7dd3fc;\n}\n\n.aktienkarte::after {\n content: '';\n position: absolute;\n inset: auto -30px -45px auto;\n width: 120px;\n height: 120px;\n background: rgba(125, 211, 252, 0.12);\n border-radius: 50%;\n}\n\n.aktienkopf {\n display: flex;\n justify-content: space-between;\n gap: 0.5rem;\n}\n\n.symbol {\n color: #bae6fd;\n font-weight: 800;\n letter-spacing: 0.08rem;\n}\n\n.preis {\n font-size: 1.8rem;\n font-weight: 800;\n margin: 0.5rem 0;\n}\n\n.trendPlus {\n color: #86efac;\n}\n\n.trendMinus {\n color: #fca5a5;\n}\n\n.aktionen {\n display: flex;\n gap: 0.5rem;\n margin-top: 0.8rem;\n}\n\n.aktionen button {\n flex: 1;\n padding: 0.55rem 0.7rem;\n}\n.watch-button {\n flex: 1;\n padding: 0.55rem 0.7rem;\n background: linear-gradient(135deg, #a78bfa, #c084fc);\n}\n\n.watchlist-container {\n display: grid;\n gap: 0.6rem;\n margin-bottom: 1.2rem;\n}\n\n.watchlist-eintrag {\n background: rgba(255,255,255,0.07);\n border: 1px solid rgba(255,255,255,0.1);\n border-radius: 18px;\n padding: 0.85rem;\n}\n\n\ncanvas {\n width: 100%;\n max-height: 310px;\n background: rgba(2, 6, 23, 0.45);\n border-radius: 18px;\n border: 1px solid rgba(255,255,255,0.1);\n}\n\n.hinweis {\n color: #94a3b8;\n font-size: 0.9rem;\n margin-top: 0.7rem;\n}\n\n.seitenleiste {\n grid-row: span 2;\n}\n\n.depotListe,\n.nachrichtenListe,\n.botListe {\n display: grid;\n gap: 0.6rem;\n margin-bottom: 1.2rem;\n}\n\n.nachricht {\n border-left: 4px solid #38bdf8;\n}\n\n.bot {\n display: flex;\n justify-content: space-between;\n gap: 0.5rem;\n}\n\n.leer {\n color: #94a3b8;\n border: 1px dashed rgba(255,255,255,0.2);\n border-radius: 16px;\n padding: 0.8rem;\n}\n\n.startBildschirm {\n position: fixed;\n inset: 0;\n background: rgba(2, 6, 23, 0.92);\n backdrop-filter: blur(8px);\n display: flex;\n justify-content: center;\n align-items: center;\n z-index: 1000;\n}\n\n.startInhalt {\n background: rgba(15, 23, 42, 0.85);\n border: 1px solid rgba(125, 211, 252, 0.35);\n border-radius: 28px;\n padding: 2.5rem;\n max-width: 600px;\n text-align: center;\n box-shadow: 0 25px 60px rgba(0,0,0,0.4);\n}\n\n.startInhalt h2 {\n font-size: 2.2rem;\n margin-bottom: 1.2rem;\n color: #7dd3fc;\n}\n\n.startInhalt p {\n color: #cbd5e1;\n line-height: 1.6;\n margin-bottom: 1.8rem;\n}\n\n.startInhalt button {\n padding: 0.85rem 2rem;\n font-size: 1.1rem;\n background: linear-gradient(135deg, #38bdf8, #818cf8);\n}\n\n@media (max-width: 900px) {\n .kopfbereich,\n .hero,\n .layout {\n display: block;\n }\n\n .marktkarte,\n .panel {\n margin-top: 1rem;\n }\n\n .kennzahlen,\n .steuerung {\n margin-top: 1rem;\n }\n\n .steuerung {\n flex-direction: row;\n flex-wrap: wrap;\n }\n}\n\n@media (max-width: 560px) {\n .kopfbereich {\n padding: 1rem;\n }\n\n .layout {\n padding: 0.6rem;\n }\n\n .kennzahlen {\n grid-template-columns: 1fr;\n }\n\n button {\n width: 100%;\n }\n}","isMain":false}]}]