Instrumentensuche

Die meisten Connectors zu US-Aktienbörsen (zum Beispiel Interactive Brokers, PolygonIO und andere) übertragen nach dem Herstellen einer Verbindung über die Methode IConnector.Connect nicht alle verfügbaren Instrumente an den Client. Grund dafür ist die große Anzahl von Instrumenten, die an amerikanischen Börsen gehandelt werden; außerdem wird so die Last auf Broker-Servern und Datenquellen reduziert.

Grundlagen der Instrumentensuche

Für die Suche nach Instrumenten in S# wird ein Abonnementmechanismus verwendet, ähnlich wie beim Empfang von Marktdaten. Dieser Ansatz ermöglicht einheitlichen Code für alle Datentypen, einschließlich Instrumenten.

Erstellen eines Abonnements für die Instrumentensuche

Um nach Instrumenten zu suchen, müssen Sie eine Instanz der Klasse Subscription auf Basis der Nachricht SecurityLookupMessage erstellen, die Filterparameter enthält:

// Filterobjekt für die Suche erstellen
var lookupMessage = new SecurityLookupMessage
{
	// Suchkriterien festlegen
	SecurityId = new SecurityId
	{
		// Suche nach Instrumentencode (Sie können eine Maske wie "AAPL*" verwenden)
		SecurityCode = "AAPL",
		// Optional kann der Board-Code angegeben werden
		BoardCode = "NASDAQ"
	},
	// Der Instrumententyp kann angegeben werden
	SecurityType = SecurityTypes.Stock,
	// Transaktions-ID setzen
	TransactionId = Connector.TransactionIdGenerator.GetNextId()
};

// Abonnement für die Instrumentensuche erstellen
var subscription = new Subscription(lookupMessage);

Mögliche Filterparameter

Die Nachricht SecurityLookupMessage erlaubt das Festlegen folgender Suchkriterien:

  • SecurityId - Instrumentenbezeichner, bestehend aus:
    • SecurityCode - Code oder Maske des Instrumentencodes (zum Beispiel "AAPL" oder "MS*")
    • BoardCode - Börsen-Board-Code (zum Beispiel ExchangeBoard.Nasdaq)
  • SecurityType - Instrumententyp (SecurityTypes.Stock, SecurityTypes.Future usw.)
  • SecurityTypes - Array von Instrumententypen für erweiterte Suche
  • Currency - Handelswährung des Instruments
  • ExpiryDate - Verfallsdatum (für Derivate)
  • Strike - Ausübungspreis (für Optionen)
  • OptionType - Optionstyp (für Optionen)
  • Name - Instrumentenname oder ein Teil davon
  • Class - Instrumentenklasse

Verarbeitung von Suchergebnissen

Nach dem Erstellen des Abonnements müssen Sie Ereignisse für den Empfang von Instrumenten abonnieren und die Anfrage senden:

// Handler für das Instrumentenempfangsereignis
private void OnSecurityReceived(Subscription subscription, Security security)
{
	if (subscription.SubscriptionMessage is not SecurityLookupMessage)
		return;

	Console.WriteLine($"Instrument gefunden: {security.Id} - {security.Name}, Typ: {security.Type}");

	// Hier können Sie das Instrument zu einer Sammlung hinzufügen oder andere Aktionen ausführen
	Securities.Add(security);
}

// Handler für das Ereignis zum Abschluss der Suche
private void OnSubscriptionFinished(Subscription subscription)
{
	if (subscription.SubscriptionMessage is not SecurityLookupMessage)
		return;

	Console.WriteLine($"Suche abgeschlossen. Gefundene Instrumente: {Securities.Count}");
}

// Handler für Abonnementfehler
private void OnSubscriptionFailed(Subscription subscription, Exception error, bool isSubscribe)
{
	if (subscription.SubscriptionMessage is not SecurityLookupMessage)
		return;

	Console.WriteLine($"Fehler bei der Instrumentsuche: {error.Message}");
}

// Ereignisse abonnieren
Connector.SecurityReceived += OnSecurityReceived;
Connector.SubscriptionFinished += OnSubscriptionFinished;
Connector.SubscriptionFailed += OnSubscriptionFailed;

// Anfrage zur Instrumentensuche senden
Connector.Subscribe(subscription);

Vollständiges Beispiel für die Instrumentensuche

Unten sehen Sie ein vollständiges Beispiel einer Methode zur Suche nach Instrumenten:

public void FindSecurities(string searchCode, SecurityTypes? securityType = null)
{
	// Objekt für die Instrumentensuche erstellen
	var lookupMessage = new SecurityLookupMessage
	{
		SecurityId = new SecurityId
		{
			SecurityCode = searchCode,
			// Wenn auf einem bestimmten Board gesucht werden soll
			// BoardCode = ExchangeBoard.Nyse.Code,
		},
		SecurityType = securityType,
		TransactionId = Connector.TransactionIdGenerator.GetNextId()
	};

	// Abonnement erstellen
	var subscription = new Subscription(lookupMessage);

	// Sammlung für Suchergebnisse leeren
	_searchResults.Clear();

	// Temporäre Sammlung zum Sammeln der Ergebnisse
	var foundSecurities = new List<Security>();

	// Abonnement für den Empfang von Instrumenten
	void OnSecurityReceived(Subscription sub, Security security)
	{
		if (sub != subscription)
			return;

		// Gefundenes Instrument zur Sammlung hinzufügen
		foundSecurities.Add(security);
		Console.WriteLine($"Gefunden: {security.Id}, {security.Name}");
	}

	// Abonnement für den Abschluss der Suche
	void OnSubscriptionFinished(Subscription sub)
	{
		if (sub != subscription)
			return;

		// Ergebnisse in die Hauptsammlung kopieren
		_searchResults.AddRange(foundSecurities);

		Console.WriteLine($"Suche abgeschlossen. Gefundene Instrumente: {foundSecurities.Count}");

		// Ereignisse abbestellen
		Connector.SecurityReceived -= OnSecurityReceived;
		Connector.SubscriptionFinished -= OnSubscriptionFinished;
		Connector.SubscriptionFailed -= OnSubscriptionFailed;
	}

	// Behandlung von Abonnementfehlern
	void OnSubscriptionFailed(Subscription sub, Exception error, bool isSubscribe)
	{
		if (sub != subscription)
			return;

		Console.WriteLine($"Fehler bei der Instrumentsuche: {error.Message}");

		// Ereignisse abbestellen
		Connector.SecurityReceived -= OnSecurityReceived;
		Connector.SubscriptionFinished -= OnSubscriptionFinished;
		Connector.SubscriptionFailed -= OnSubscriptionFailed;
	}

	// Ereignisse abonnieren
	Connector.SecurityReceived += OnSecurityReceived;
	Connector.SubscriptionFinished += OnSubscriptionFinished;
	Connector.SubscriptionFailed += OnSubscriptionFailed;

	// Suchanfrage senden
	Connector.Subscribe(subscription);
}

Verwendungsbeispiel in einer WPF-Anwendung

In einer grafischen Anwendung wird die Instrumentensuche häufig aus einem Button-Click-Handler aufgerufen:

private void FindButton_Click(object sender, RoutedEventArgs e)
{
	// Suchkriterium aus dem Textfeld abrufen
	var searchText = SearchTextBox.Text;

	if (string.IsNullOrWhiteSpace(searchText))
	{
		MessageBox.Show("Enter a search criterion");
		return;
	}

	// Suchabonnement erstellen und senden
	var lookupMessage = new SecurityLookupMessage
	{
		SecurityId = new SecurityId { SecurityCode = searchText },
		// Wenn im Interface ein Typ ausgewählt ist
		SecurityType = SecurityTypeComboBox.SelectedItem as SecurityTypes?
	};

	var subscription = new Subscription(lookupMessage);

	// Hier kann ein Ladeindikator angezeigt werden
	LoadingIndicator.Visibility = Visibility.Visible;

	// Anfrage senden
	Connector.Subscribe(subscription);
}

Verwenden von SecurityLookupWindow

StockSharp stellt außerdem einen fertigen Dialog für die Instrumentensuche bereit - SecurityLookupWindow:

private void ShowSecurityLookupWindow_Click(object sender, RoutedEventArgs e)
{
	var lookupWindow = new SecurityLookupWindow
	{
		// Möglichkeit zur Suche nach allen Instrumenten angeben
		// (wenn der Connector diese Funktion unterstützt)
		ShowAllOption = Connector.Adapter.IsSupportSecuritiesLookupAll(),

		// Anfangs-Suchkriterien festlegen
		CriteriaMessage = new SecurityLookupMessage
		{
			SecurityId = new SecurityId { SecurityCode = "AAPL" },
			SecurityType = SecurityTypes.Stock
		}
	};

	// Fenster als modalen Dialog anzeigen
	if (lookupWindow.ShowModal(this))
	{
		// Wenn der Benutzer die Auswahl bestätigt hat, Anfrage senden
		Connector.Subscribe(new Subscription(lookupWindow.CriteriaMessage));
	}
}

Fazit

Der Abonnementmechanismus in StockSharp bietet einen einheitlichen Weg zum Abrufen von Daten, einschließlich der Instrumentensuche. Dadurch kann derselbe Ansatz für die Arbeit mit verschiedenen Connectors und Datentypen verwendet werden, was die Entwicklung von Handelsanwendungen deutlich vereinfacht.