Aktienkurse

Für welche Projekte verwendet Ihr OpenHAB? Was habt Ihr automatisiert? Stellt eure Projekte hier vor.

Moderatoren: Cyrelian, seppy

Benutzeravatar
guinnes
Beiträge: 146
Registriert: 21. Apr 2020 19:46

Aktienkurse

Beitrag von guinnes »

Moin
Es ist sicherlich nicht das Ziel von Openhab, Aktienkurse zu verarbeiten, aber da Openhab wohl normalerweise 24/7 läuft, bietet sich die Erfassung von Kursen eigentlich ab. Hier mein Wertpapierprojekt :
Die Kurse werden von einer zeitgesteuerten Rule erfasst und direkt in die Items geschrieben. Dafür müßen die Namen der Items einem Schema folgen :
Die ISIN-Nummer gefolgt von _Name für den Wertpapiernamen, _Geld für Nachfrage, _Brief für Angebot und _Delta für die Veränderung zum Vortag. Es können nur Listen eingelesen werden : DAX, MDAX, TecDAX, SDAX usw. Weiterhin besteht die Möglichkeit, alle Aktien mit einem bestimmten Anfangsbuchstaben einzulesen. Es müßen nur Items erzeugt werden, von Aktien, die euch interessieren. Die Daten kommen von Tradegate und sind kostenlos. Es gibt keine API, die Daten werden aus den HTML-Seiten geparst. Hier Beispiele für die Items : ( Die GRuppe ist noch wichtig, darüber erreicht ich die Items )

Code: Alles auswählen

Group   g_Stock               "Aktien Items"
// Allianz
String   DE0008404005_Name       (g_Stock) 
Number   DE0008404005_Geld       (g_Stock)
Number   DE0008404005_Brief      (g_Stock)
Number   DE0008404005_Delta      (g_Stock)
// BASF
String   DE000BASF111_Name       (g_Stock) 
Number   DE000BASF111_Geld       (g_Stock)
Number   DE000BASF111_Brief      (g_Stock)
Number   DE000BASF111_Delta      (g_Stock)
// Daimler
String   DE0007100000_Name       (g_Stock) 
Number   DE0007100000_Geld       (g_Stock)
Number   DE0007100000_Brief      (g_Stock)
Number   DE0007100000_Delta      (g_Stock)
// Telekom
String   DE0005557508_Name       (g_Stock) 
Number   DE0005557508_Geld       (g_Stock)
Number   DE0005557508_Brief      (g_Stock)
Number   DE0005557508_Delta      (g_Stock)
// Linde
String   IE00BZ12WP82_Name       (g_Stock) 
Number   IE00BZ12WP82_Geld       (g_Stock)
Number   IE00BZ12WP82_Brief      (g_Stock)
Number   IE00BZ12WP82_Delta      (g_Stock)
// RWE
String   DE0007037129_Name       (g_Stock) 
Number   DE0007037129_Geld       (g_Stock)
Number   DE0007037129_Brief      (g_Stock)
Number   DE0007037129_Delta      (g_Stock)
// SAP
String   DE0007164600_Name       (g_Stock) 
Number   DE0007164600_Geld       (g_Stock)
Number   DE0007164600_Brief      (g_Stock)
Number   DE0007164600_Delta      (g_Stock)
// Siemens
String   DE0007236101_Name       (g_Stock) 
Number   DE0007236101_Geld       (g_Stock)
Number   DE0007236101_Brief      (g_Stock)
Number   DE0007236101_Delta      (g_Stock)
Hier die Rule :

Code: Alles auswählen

val Get_Stock_Data  =       
[ String HTTPAddr    // HTTP-Adresse, von der wir die Daten holen wollen
  |
  var String[] werte // Die HTML-Zeilen der einzelnen Päckchen der Aktienwerte
  var String wert    // Die eine Zeile eines Wertes
  var String hs      // Allgemeiner HilfsString
  var Integer count  // Anzahl der Aktienwerte
  var Integer i      // Die Schleifenvariable

  var response = sendHttpGetRequest(HTTPAddr)   
  var lBody    = response.substring(response.indexOf('<tbody') , response.indexOf('</tbody>'));

  werte = lBody.split('<tr') // Aufteilen in Päckchen mit den Werten Pro Aktie
  count = werte.size
  logInfo("Aktiendaten", "Anzahl {}",count)
  for (i=1; i<count; i++){
    var String isin   // String für die ISIN
    var String name   // String für den Wertpapiernamen
    var String bid    // String für Nachfrage
    var String ask    // String für Angebot
    var String delta  // String für Veränderung zum Vortag
    wert = werte.get(i)
    hs = wert.substring(wert.indexOf('id="name'), wert.indexOf('</td>')) // Den String mit ISIN und Namen rausschneiden
    isin = hs.substring(hs.indexOf('isin='), hs.indexOf('</a>'))
    name = isin.substring(isin.indexOf('">') + 2, isin.length)
    isin = isin.substring(5, isin.indexOf('">'))
    hs = wert.substring(wert.indexOf('<td id="bid'), wert.indexOf('<td id="ask'))
    bid = hs.substring(hs.indexOf('">') + 2, hs.indexOf('</td>'))
    bid = bid.replace(',','.')
    hs = wert.substring(wert.indexOf('<td id="ask'), wert.indexOf('<td id="sum'))
    ask = hs.substring(hs.indexOf('">') + 2, hs.indexOf('</td>'))
    ask = ask.replace(',','.')
    hs = wert.substring(wert.indexOf('<td id="delta'), wert.indexOf('%</td>'))
    delta = hs.substring(hs.indexOf('">') + 2, hs.length)
    delta = delta.replace(',','.')
    logInfo("Aktiendaten","ISIN {} Name {} Geld {} Brief {} Delta {}",isin,name,bid,ask,delta)

    val String visin = isin  // Nur, damit die Fehlermeldungen in VSCode verschwinden
    var wtemp = g_Stock.members.findFirst[j | j.name == visin + "_Name"]
  	if (wtemp !== null) {
      wtemp.postUpdate(name) 
    }  
    wtemp = g_Stock.members.findFirst[j | j.name == visin + "_Geld"]
  	if (wtemp !== null) {
      wtemp.postUpdate(bid) 
    }
    wtemp = g_Stock.members.findFirst[j | j.name == visin + "_Brief"]
  	if (wtemp !== null) {
      wtemp.postUpdate(ask) 
    }
    wtemp = g_Stock.members.findFirst[j | j.name == visin + "_Delta"]
  	if (wtemp !== null) {
      wtemp.postUpdate(delta) 
    }
  }
]

/*
Weitere Adressen, von denen man Kurse holen kann
"https://www.tradegate.de/indizes.php?index=DE000A1EXRV0"   // DAX
"https://www.tradegate.de/indizes.php?index=DE000A1EXRW8"   // MDAX
"https://www.tradegate.de/indizes.php?index=DE000A1EXRY4"   // TECDAX
"https://www.tradegate.de/indizes.php?index=DE000A1EXRX6"   // SDAX
"https://www.tradegate.de/indizes.php?index=EU0009658145"   // Eurostock 50
"https://www.tradegate.de/indizes.php?index=US0000000002"   // US-Top-Titel
"https://www.tradegate.de/indizes.php?buchstabe=A"          // Alle Aktien die Mit A anfangen
*/

rule "Aktienkurse Tradegate"
when 
   Time cron "0 * * * * ?"
then
    Get_Stock_Data.apply("https://www.tradegate.de/indizes.php?index=DE000A1EXRV0")  // DAX 
end
Natürlich können auch mehrere Listen hintereinander eingelesen werden, darum das Unterprogramm

Ich hoffe, es hilft

Glückauf
guinnes
Glückauf
guinnes

Benutzeravatar
PeterA
Beiträge: 1052
Registriert: 8. Feb 2019 12:12
Answers: 13

Re: Aktienkurse

Beitrag von PeterA »

Moin guinnes,

witzig was man mit OH alles so treiben kann :D
Ich hatte es mal in OH eingebaut aber beim Aufruf über die
Gruppe in der Sitemap keine Werte usw angezeigt bekommen.
Obwohl die Rule brav alles in die Items geschrieben hat.

Gruß Peter
- OpenHab 2.4
#PWRUP

Benutzeravatar
guinnes
Beiträge: 146
Registriert: 21. Apr 2020 19:46

Re: Aktienkurse

Beitrag von guinnes »

Moin
Ich zeige in der Sitemap auch nicht die Gruppe an sondern die Items

Glückauf
guinnes
Glückauf
guinnes

Benutzeravatar
PeterA
Beiträge: 1052
Registriert: 8. Feb 2019 12:12
Answers: 13

Re: Aktienkurse

Beitrag von PeterA »

Ok,

noch ein Kurzes Code Snippet Deiner Sitemap vielleicht?

Merci
- OpenHab 2.4
#PWRUP

Benutzeravatar
guinnes
Beiträge: 146
Registriert: 21. Apr 2020 19:46

Re: Aktienkurse

Beitrag von guinnes »

Kein Problem, ich hab allerding das Zeug mittlerweile erweitert :
Sitemap :

Code: Alles auswählen

      Group item=g_Stock label="Aktienkurse" {
        Frame label="Allianz" {  
          Chart item=g_Allianz  label="" refresh=60000 period=D service="rrd4j"
          Text  item=DE0008404005_Name
          Text  item=DE0008404005_Geld
          Text  item=DE0008404005_Brief
          Text  item=DE0008404005_Delta
          Text  item=DE0008404005_Anzahl
          Text  item=DE0008404005_Kauf
          Text  item=DE0008404005_Wert
          Text  item=DE0008404005_Gewinn
          Group item=g_Allianz label="Kaufpreis/Anzahl ändern" {
            Frame label="Kaufpreis/Anzahl ändern" {
      	      Webview icon="zertifikat" url="http://192.168.178.27:8080/static/textInput.html?item=DE0008404005_Anzahl&label=Anzahl" height=1
	            Webview icon="euro" url="http://192.168.178.27:8080/static/textInput.html?item=DE0008404005_Kauf&label=Kaufpreis" height=1
            }
          }
        }
        Frame label="BASF" {
          Chart item=g_BASF  label="" refresh=60000 period=D service="rrd4j"
          Text  item=DE000BASF111_Name
          Text  item=DE000BASF111_Geld
          Text  item=DE000BASF111_Brief
          Text  item=DE000BASF111_Delta
          Text  item=DE000BASF111_Anzahl
          Text  item=DE000BASF111_Kauf
          Text  item=DE000BASF111_Wert
          Text  item=DE000BASF111_Gewinn
          Group item=g_BASF label="Kaufpreis/Anzahl ändern" {
            Frame label="Kaufpreis/Anzahl ändern" {
      	      Webview icon="zertifikat" url="http://192.168.178.27:8080/static/textInput.html?item=DE000BASF111_Anzahl&label=Anzahl" height=1
	            Webview icon="euro" url="http://192.168.178.27:8080/static/textInput.html?item=DE000BASF111_Kauf&label=Kaufpreis" height=1
            }
          }
        }
 ......
Items :

Code: Alles auswählen

Group   g_Stock     "Aktien Items" <zertifikat>
Group   g_Allianz                  <allianz>
Group   g_BASF                     <basf>
Group   g_Daimler                  <daimler>
Group   g_Telekom                  <telekom>
Group   g_Linde                    <linde>
Group   g_RWE                      <rwe>
Group   g_SAP                      <sap>
Group   g_Siemens                  <siemens>

// Allianz
String   DE0008404005_Name   "Name [%s]"            <allianz>     (g_Stock) 
Number   DE0008404005_Geld   "Geld [%.2f €]"        <euro>        (g_Stock,P_1Min,g_Allianz)
Number   DE0008404005_Brief  "Brief [%.2f €]"       <zertifikat>  (g_Stock,P_1Min,g_Allianz)
Number   DE0008404005_Delta  "Veränderung zum Vortag [%.2f %%]"   (g_Stock,P_1Min)
Number   DE0008404005_Anzahl "Anzahl der Aktien [%.0f Stück]"     (g_Stock)  
Number   DE0008404005_Kauf   "Gesammt Kaufpreis [%.3f €]"         (g_Stock)
Number   DE0008404005_Wert   "Wert Jetzt [%.2f €]"                (g_Stock)
Number   DE0008404005_Gewinn "Veränderung [%.2f %%]"              (g_Stock)
// BASF
String   DE000BASF111_Name   "Name [%s]"            <basf>        (g_Stock)
Number   DE000BASF111_Geld   "Geld [%.2f €]"        <euro>        (g_Stock,P_1Min,g_BASF)
Number   DE000BASF111_Brief  "Brief [%.2f €]"       <zertifikat>  (g_Stock,P_1Min,g_BASF)
Number   DE000BASF111_Delta  "Veränderung zum Vortag [%.2f %%]"   (g_Stock,P_1Min)
Number   DE000BASF111_Anzahl "Anzahl der Aktien [%.0f Stück]"     (g_Stock)
Number   DE000BASF111_Kauf   "Gesammt Kaufpreis [%.3f €]"         (g_Stock)
Number   DE000BASF111_Wert   "Wert Jetzt [%.2f €]"                (g_Stock)
Number   DE000BASF111_Gewinn "Veränderung [%.2f %%]"              (g_Stock)
......
zusätliches Unterprogramm in den Rules :

Code: Alles auswählen

val Set_Stock_Value  =       
[ String Isin    // Isin der Aktie
  |
  var NumberItem brief
  var NumberItem anzahl
  var NumberItem aktienwert
  var NumberItem kauf
  var NumberItem gewinn
  var float wert

  brief = g_Stock.members.findFirst[j | j.name == Isin + "_Brief"] as NumberItem
  if (brief !== null) {
    anzahl = g_Stock.members.findFirst[j | j.name == Isin + "_Anzahl"] as NumberItem
    if (brief !== null) {
      aktienwert = g_Stock.members.findFirst[j | j.name == Isin + "_Wert"] as NumberItem
      if (aktienwert !== null) {
        kauf = g_Stock.members.findFirst[j | j.name == Isin + "_Kauf"] as NumberItem
        if (kauf !== null) {
          gewinn = g_Stock.members.findFirst[j | j.name == Isin + "_Gewinn"] as NumberItem
          if (gewinn !== null) {
            wert = (brief.state as Number).floatValue * (anzahl.state as Number).floatValue
            aktienwert.postUpdate(wert)
            if ((kauf.state as Number).floatValue > 0) {
              wert = (wert / (kauf.state as Number).floatValue) - 1
              gewinn.postUpdate(wert * 100)
            }
          }
        }
      }
    }
  }  
]
Rules :

Code: Alles auswählen

rule "Allianz"
when
  Item DE0008404005_Brief changed
then
  Set_Stock_Value.apply("DE0008404005")
end

rule "BASF"
when
  Item DE000BASF111_Brief changed
then
  Set_Stock_Value.apply("DE000BASF111")
end

rule "Daimler"
when
  Item DE0007100000_Brief changed
then
  Set_Stock_Value.apply("DE0007100000")
end
....
Und noch der HTML-Quelltext für die Eingaben :( sieht schlimm aus, ist es auch, aber ich nichts besseres gefunden )
textInput.html

Code: Alles auswählen

<html class="ui-icons-enabled">
<script>
    var openHabianPI = "192.168.178.27"
    function getParam(param)
    {
        var qs = (function(a) {
            if (a == "") return {};
            var b = {};
            for (var i = 0; i < a.length; ++i) {
                var p=a[i].split('=', 2);
                if (p.length == 1)
                    b[p[0]] = "";
                else
                    b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
            }
            return b;
        })(window.location.search.substr(1).split('&'));       
        return qs[param]
    }
    function httpGet(theUrl)
    {
        var xmlHttp = new XMLHttpRequest();
        xmlHttp.onreadystatechange = function() {
    		if (this.readyState == 4 && this.status == 200) {
		    	document.getElementById('textInput').value = xmlHttp.responseText;
		    }
		};
        xmlHttp.open("GET", theUrl, true);
        xmlHttp.setRequestHeader("Accept", "text/plain");
        xmlHttp.send();
        return 
    }
    function httpPut(theUrl, theValue)
    {
        var xmlHttp = new XMLHttpRequest();
        xmlHttp.open("PUT", theUrl, true);
        xmlHttp.setRequestHeader("Content-type", "text/plain");
        xmlHttp.setRequestHeader("Accept", "application/json");
        xmlHttp.send(theValue)
    }
	function sendValue()
	{
        url = "http://" + openHabianPI + ":8080/rest/items/" + getParam('item') + "/state";
        httpPut(url, document.getElementById('textInput').value)
    }
	function getValue()
	{
        url = "http://" + openHabianPI + ":8080/rest/items/" + getParam('item') + "/state";
        httpGet(url)
    }
</script>
<head>

	<link rel="stylesheet" type="text/css" href="../basicui/mdl/material.min.css" />
	<link rel="stylesheet" type="text/css" href="../basicui/material-icons.css" />
	<link rel="stylesheet" type="text/css" href="../basicui/roboto.css" />
	<link rel="stylesheet" type="text/css" href="../basicui/smarthome.css" />
	<script src="../basicui/mdl/material.min.js"></script>
	
	<style>
		form {
			margin-bottom: 0;
		}
		.mdl-form__row {
			border-bottom-style: none;
			height: auto;
			padding-top: 0;
			padding-right: 0;
			padding-bottom: 0;
			padding-left: 0;
		}
	</style>
</head>
<body class="mdl-color-text--grey-700" data-icon-type="svg">
	<form action="JavaScript:sendValue()">
		<div class="mdl-form__row mdl-cell mdl-cell--6-col mdl-cell--8-col-tablet">
			<span class="mdl-form__icon">
				<img data-icon="text" src="../icon/text?format=svg" />
			</span>
			<div class="mdl-form__label" id=label>
			</div>
			<div>
				<input type="text" name="textInput" id="textInput">
			</div>
			<div>
				<input type="submit" value="Submit">
			</div>
		</div>
		<script>
			document.getElementById('label').innerHTML = getParam('label');
			document.getElementById('textInput').value = getValue()
		</script>
	</form>
</body>
</html>
Glückauf
guinnes

juschi
Beiträge: 13
Registriert: 23. Mär 2020 21:49

Re: Aktienkurse

Beitrag von juschi »

Ich hab mich auch mal mit dem Thema befasst. Deine Programmierung war mir jedoch etwas zu "kompliziert". Ich erfasse die Werte direkt per Regel über HTTP. Hier ein Beispiel:

Code: Alles auswählen

rule	"Deutz"
when    Time cron "0 0/1 * * * ?"
then    val String deutz_data = sendHttpGetRequest("https://www.tradegate.de/refresh.php?isin=DE0006305006")
	var String deutz_price = transform("JSONPATH", ".['bid']", deutz_data)
	stock_deutz_price.postUpdate(Float::parseFloat(String::format("%s",deutz_price).replace(',','.')))
end
Das reicht für meine Bedürfnisse schon aus. Wenn man dann noch täglich eine Schwellenmeldung über den Gewinn (hoffentlich) erhalten will, hab ich das über folgende Regel dargestellt:

Code: Alles auswählen

var Number deutz_push = 0

rule	"Deutz Push"
when    Item stock_deutz_price changed or Time cron "0 0 0 ? * * *"	
then    var Number hour = now.getHour
	val Number buy = X.XX
	val Number now = stock_deutz_price.state as Number
	val Number change = ((now / buy) - 1) * 100
	if (deutz_push == 0) {
		if (change >=  5) 	{ 	deutz_push = 1
							sendNotification("MAIL", "Deutz stieg um: " + String.format("%.2f",change) + " %") }
		if (change <= -5) 	{ 	deutz_push = 1
							sendNotification("MAIL", "Deutz fiel um: "  + String.format("%.2f",change) + " %") } }
	if (deutz_push == 1) {
		if (change >=  10) 	{ 	deutz_push = 2
							sendNotification("MAIL", "Deutz stieg um: " + String.format("%.2f",change) + " %") }
		if (change <= -10) 	{ 	deutz_push = 2
							sendNotification("MAIL", "Deutz fiel um: "  + String.format("%.2f",change) + " %") } }
		if (hour == 0)   		{ 	deutz_push = 0 }
end
Eventuell hilft das jemanden der auf der Suche nach einer einfachen Lösung ist ;)
(Bereits in OH3 umgesetzt)

Benutzeravatar
guinnes
Beiträge: 146
Registriert: 21. Apr 2020 19:46

Re: Aktienkurse

Beitrag von guinnes »

Moin
Das mit der JSON-Seite ist natürlich genial, werd ich mal probieren. Macht die ganze Sache sehr viel übersichtlicher, Danke dafür
Glückauf
guinnes

rudolfachter
Beiträge: 2
Registriert: 22. Mai 2021 15:00

Re: Aktienkurse

Beitrag von rudolfachter »

Sowas hier hab ich gesucht!

Ich will mich von "meinen Haus Benachrichtigen lassen" wenn Aktien bestimmte Werte erreichen. Lampen Rot oder Grün blinken lassen oder so etwas.
Mir fehlte nur das Puzzlestück wie ich vernünftig an die Aktienkurse ran komme.

Ich bin zwar kein Java Mensch, ich tue mich noch schwer einfache Regeln (.rules) in Openhab zu schreiben, aber ich kann die OpenHab API via Powershell steuern. Da wirds wohl von mir eine Powershell Variante geben

Danke an alle für die Beiträge hier.

rudolfachter
Beiträge: 2
Registriert: 22. Mai 2021 15:00

Re: Aktienkurse

Beitrag von rudolfachter »

Ich hab die erste Version meines Powershell Moduls fertig.
Hiermit werde ich die Daten an OpenHab -> Grafana und keine Ahnung was noch alles Füttern.

Damit kann ich jetzt z.B. so was hier machen

Dieser Einzeiler

Code: Alles auswählen

Get-TradeGateValues -Index (Get-TradeGateIndex -Name Beyond*) | Format-Table -AutoSize
Liefert das hier zurück

Code: Alles auswählen

Name                           Isin            bid   ask bidsize asksize delta  stueck umsatz     avg
----                           ----            ---   --- ------- ------- -----  ------ ------     ---
Beyond Air Inc.                US08862L1035   4,08  4,34     540     510 +0,95%     28    118    4,23
Beyond Meat Inc.               US08862E1091  86,97 87,99      40      40 -0,68%  10379 921186 88,7548
Beyond Medical Technolog. Inc. CA0886411051 0,0594  0,07   68000   58000 0,00%       0      0     ./.
Und das was zurückkommt sind weiterverwendbare Objekte. Ich kann stattdessen z.B. auch sowas machen

Code: Alles auswählen

Get-TradeGateValues -Index (Get-TradeGateIndex -Name Beyond*) | ConvertTo-Json
Dokumentation und Code ist hier:
https://github.com/RudolfAchter/TradeGate-PS

TomW80
Beiträge: 60
Registriert: 7. Mai 2021 19:11

Re: Aktienkurse

Beitrag von TomW80 »

juschi hat geschrieben: 29. Jan 2021 18:00 Ich hab mich auch mal mit dem Thema befasst. Deine Programmierung war mir jedoch etwas zu "kompliziert". Ich erfasse die Werte direkt per Regel über HTTP. Hier ein Beispiel:

Code: Alles auswählen

rule	"Deutz"
when    Time cron "0 0/1 * * * ?"
then    val String deutz_data = sendHttpGetRequest("https://www.tradegate.de/refresh.php?isin=DE0006305006")
	var String deutz_price = transform("JSONPATH", ".['bid']", deutz_data)
	stock_deutz_price.postUpdate(Float::parseFloat(String::format("%s",deutz_price).replace(',','.')))
end
Das funktioniert so leider nicht mehr, erhalte ich immer folgenden Fehler
2024-01-09 09:31:01.011 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'aktien-1' failed: For input string: "{
"bid": 14.35.
"ask": 14.38.
"bidsize": 600.
"asksize": 600.
"delta": 0.49.
"stueck": 2100.
"umsatz": 30207.
"avg": 14.3842.
"executions": 8.
"last": 14.42.
"high": 14.42.
"low": 14.34.
"close": 14.35.
"refresh": 10
}" in aktien
Der Fehler muss hier "var String deutz_price = transform("JSONPATH", ".['bid']", deutz_data)" liegen.
Das sollte ja nur den Inhalt von bid zurückliefern oder?

Antworten