Dokumentation

Anwendungen

Zuletzt aktualisiert am 10. 2. 2022 von Mark Fric

Datenbankergebnisse in DB speichern

In diesem Beispiel geht es um die Speicherung von Datenbankinhalten in einer Datenbank, die als CustomAnalysis-Snippet implementiert ist.

 

Hinweis! Es gab einen kleinen Fehler in der ursprünglichen Erweiterung - sie verwendete ein Paket, das in der veröffentlichten Version von SQ X noch nicht verfügbar war. Bitte laden Sie das Snippet erneut herunter.

 

Der Einfachheit halber verwendet es SQLite DB, aber es ist kein Problem, MySql oder MariaDB oder eine andere Datenbank zu verwenden, da es die JDBC-Datenbankverbindung verwendet, die ein Java-Standard für die Verbindung und Kommunikation mit Datenbanken ist.
Wenn Sie eine andere Datenbank verwenden, müssen Sie dies tun:

  • ändern Sie die JDBC-Verbindungszeichenfolge in createDBConnection() Methode
  • Es könnte notwendig sein, die JDBC-Bibliothek für Ihre Zieldatenbank hinzuzufügen - SQLite ist bereits in SQX enthalten, aber Datenbanken wie MySql oder MariaDB sind es nicht - also müssen Sie deren JDBC-Bibliothek finden (etwas wie https://dev.mysql.com/downloads/connector/j/ und fügen Sie die JAR-Datei(en) in den Ordner {StrategyQuant-Installation}/user/libs ein.

ziemlich kompliziert, weil es genau die Datenbankansicht speichert, die Sie in der Benutzeroberfläche sehen - wenn Sie die Ansicht nicht verwenden möchten, können Sie einfach Werte wie Nettogewinn, Anzahl der Trades usw. aus ResultsGroup abrufen und sie selbst speichern.

Die Hauptlogik ist eigentlich sehr einfach:

@Override
public ArrayList processDatabank(String project, String task, String databankName, ArrayList databankRG) throws Exception {
    Databank databank = ProjectEngine.get(project).getDatabanks().get(databankName);
    if(databank == null){
        throw new Exception("Datenbank " + projekt + "/" + databankName + " existiert nicht");
    }

    DatabankTableView view = databank.getView();

    String tableName = getTableName(project, task, databankName);

    try (Verbindung dbConnection = createDBConnection(tableName, view)) {
        dbConnection.setAutoCommit(false);

        try (Anweisung stmt = dbConnection.createStatement()) {
            for (int a = 0; a < databankRG.size(); a++) {
                ResultsGroup rg = databankRG.get(a);
                writeData(rg, view, tableName, stmt);
            }
        }

        dbConnection.commit();
    }

    return databankRG;
}

Der Code erstellt eine DB-Verbindung, erstellt eine Anweisung, geht dann durch die in der Datenbank gespeicherten ResultGroups und speichert jede von ihnen in der DB mit einer Standard-SQL-Anweisung.

 

Vollständiger Code des Snippets (er kann auch im Anhang zu diesem Beitrag heruntergeladen werden):

Paket SQ.CustomAnalysis;

import com.strategyquant.lib.SQTime;
import com.strategyquant.lib.SQUtils;
import com.strategyquant.tradinglib.*;
import com.strategyquant.tradinglib.databank.DatabankTableColumnEntry;
import com.strategyquant.tradinglib.databank.DatabankTableView; import com.strategyquant.tradinglib.databank.DatabankTableView;
import com.strategyquant.tradinglib.project.ProjectEngine;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;

public class SaveDatabankToDB extends CustomAnalysisMethod {

    public static final Logger Log = LoggerFactory.getLogger("SaveDatabankToDB");

    private static final String TABLE_NAME_SEPARATOR = "__";
    private static final DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("jjjj-MM-tt-HHmm");

    public static final String TABLE_NAME = "databankData";

    private static final String STRATEGY_COLUMN_NAME = "strategyName";

    //------------------------------------------------------------------------
    //------------------------------------------------------------------------
    //------------------------------------------------------------------------

    /**
     * Instanziiert eine neue benutzerdefinierte Analysemethode.
     */
    public SaveDatabankToDB() {
        super("SaveDatabankToDB", TYPE_PROCESS_DATABANK);
    }


    //------------------------------------------------------------------------

    @Override
    public boolean filterStrategy(String project, String task, String databankName, ResultsGroup rg) throws Exception {
        return true;
    }

    //------------------------------------------------------------------------

    @Override
    public ArrayList processDatabank(String project, String task, String databankName, ArrayList databankRG) throws Exception {
        Databank databank = ProjectEngine.get(project).getDatabanks().get(databankName);
        if(databank == null){
            throw new Exception("Datenbank " + projekt + "/" + databankName + " existiert nicht");
        }

        DatabankTableView view = databank.getView();

        String tableName = getTableName(project, task, databankName);

        try (Verbindung dbConnection = createDBConnection(tableName, view)) {
            dbConnection.setAutoCommit(false);

            try (Anweisung stmt = dbConnection.createStatement()) {
                for (int a = 0; a < databankRG.size(); a++) {
                    ResultsGroup rg = databankRG.get(a);
                    writeData(rg, view, tableName, stmt);
                }
            }

            dbConnection.commit();
        }

        return databankRG;
    }

    //------------------------------------------------------------------------

    public static String getOutputFolder(){
        return "C:/SQDatabankExports";
    }

    //------------------------------------------------------------------------

    private Connection createDBConnection(String tableName, DatabankTableView view) throws Exception {
        Verbindung c = null;

        try {
            Class.forName("org.sqlite.JDBC");
            String folderPath = getOutputFolder();

            SQUtils.ensureDirExists(folderPath);

            String dbPath = String.format("%s/%s.db", folderPath, tableName);
            String connectionString = String.format("jdbc:sqlite:%s", dbPath);

            c = DriverManager.getConnection(connectionString);

            tryCreateTable(c, tableName, view);
        }
        catch (Exception e ) {
            Log.error("Erstellen der Datenbankverbindung fehlgeschlagen", e);
            throw e;
        }

        return c;
    }

    //------------------------------------------------------------------------

    public static String getTableName(String projectName, String taskName, String databankName){
        String dateTime = dateTimeFormatter.print(System.currentTimeMillis());
        return dateTime + TABLE_NAME_SEPARATOR + projectName + TABLE_NAME_SEPARATOR + taskName + TABLE_NAME_SEPARATOR + databankName;
    }

    //------------------------------------------------------------------------

    private void tryCreateTable(Connection connection, String tableName, DatabankTableView view) throws Exception {
        if(view == null){
            throw new Exception("Databank View ist null");
        }

        Anweisung stmt = null;
        try {
            StringBuilder sb = new StringBuilder(STRATEGY_COLUMN_NAME).append(" TEXT PRIMARY KEY");

            ColumnNamesResolver columnNamesResolver = new ColumnNamesResolver();

            for(int a=0; a<view.columns.size(); a++){
                DatabankTableColumnEntry column = view.columns.get(a);
                String columnName = columnNamesResolver.getColumnName(column);

                sb.append(",");
                sb.append(columnName);
                sb.append(" TEXT");
            }

            String sql = String.format("CREATE TABLE IF NOT EXISTS %s (%s);", TABLE_NAME, sb);

            stmt = connection.createStatement();
            stmt.executeUpdate(sql);
        }
        finally {
            if(stmt != null) {
                stmt.close();
            }
        }
    }

    //------------------------------------------------------------------------

    private void writeData(ResultsGroup rg, DatabankTableView view, String tableName, Statement stmt) throws SQLException {
        StringBuilder columnNames = new StringBuilder();
        StringBuilder values = new StringBuilder();

        ColumnNamesResolver columnNamesResolver = new ColumnNamesResolver();

        columnNames.append(STRATEGY_COLUMN_NAME);
        values.append("'").append(rg.getName()).append("'");

        for (int a = 0; a < view.columns.size(); a++) {
            DatabankTableColumnEntry column = view.columns.get(a);
            String columnName = columnNamesResolver.getColumnName(column);
            String value = "N/A";

            try {
                value = column.tableColumn.exportValue(rg, null, Directions.Both, PlTypes.Money, SampleTypes.FullSample);
            } catch (Exception e) {
                Log.error("Fehler beim Abrufen von Werten für Strategie + " + rg.getName() + " und Spalte " + columnName, e);
            }

            columnNames.append(",").append(columnName);
            values.append(",").append("'").append(value).append("'");
        }

        String sql = String.format("INSERT INTO %s (%s) VALUES (%s)", TABLE_NAME, columnNames, values);
        stmt.executeUpdate(sql);
    }

    //------------------------------------------------------------------------

    private class ColumnNamesResolver {

        private HashMap columnNameCounts = new HashMap();

        public String getColumnName(DatabankTableColumnEntry columnEntry){
            String columnName = columnEntry.tableColumn.getClass().getSimpleName();
            String finalColumnName = null;

            //der folgende Code kümmert sich um mehrere Spalten mit demselben Namen in der Datenbankansicht
            Integer columnCount = columnNameCounts.get(columnName);
            if(columnCount != null){
                columnCount += 1;
                finalColumnName = columnName + columnCount;
            }
            sonst {
                columnCount = 1;
                finalColumnName = columnName;
            }

            columnNameCounts.put(columnName, columnCount);

            return finalColumnName;
        }

    }
}

 

War dieser Artikel hilfreich? Der Artikel war nützlich Der Artikel war nicht nützlich

Abonnieren
Benachrichtigen Sie mich bei
1 Kommentar
Älteste
Neuestes Meistgewählt
Inline-Rückmeldungen
Alle Kommentare anzeigen
Bienenhändler
25. 2. 2022 8:57 Uhr

Dies ist ein sehr gutes Beispiel. Es trägt dazu bei, die Analyse der Ergebnisse zu beschleunigen.

Verwandte Beiträge