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}]}]