Analyse von Amazon Cloud Services und Anlageportfolios

In jüngster Zeit gab es eine hohe Volatilität an den Aktienmärkten, als beispielsweise ein stabiles Papier eines bekannten Unternehmens aufgrund von Sanktionen gegen sein Management mehrere Prozent auf einmal verlieren kann oder umgekehrt, wenn ein positiver Bericht und die Erwartungen der Anleger in Bezug auf hochprofitable Dividenden in den Himmel steigen.

Wie kann festgestellt werden, ob das Eigentum an einem bestimmten Wertpapier Einnahmen oder nur Verluste und Enttäuschungen gebracht hat?

(Quelle)

In diesem Artikel werde ich Ihnen erklären, wie Sie das bereinigte Finanzergebnis für Wertpapiere identifizieren und visualisieren können.

Am Beispiel der Kundenberichterstattung Opening Broker werden wir die Analyse und Konsolidierung von Brokerage-Berichten für die Börse betrachten und die Architektur eines Cloud-Berichtssystems mit anschließender einfacher und bequemer Analyse in AWS Quicksight erstellen.

Aufgabenbeschreibung


Viele Schulungen und Unterrichtsstunden geben Aufschluss über die Notwendigkeit eines Händlerjournals, in dem alle Transaktionsparameter zur weiteren Analyse und Zusammenfassung der Handelsstrategie aufgezeichnet werden. Ich bin damit einverstanden, dass dieser Ansatz für die Arbeit an der Börse es Ihnen ermöglicht, einen Trader zu disziplinieren, sein Bewusstsein zu stärken, aber Sie auch aus einem langwierigen Prozess ermüden kann.

Ich gebe zu, dass ich zuerst sorgfältig versucht habe, den Ratschlägen des Journalings zu folgen, jede Transaktion mit ihren Parametern akribisch in eine Excel-Tabelle geschrieben, einige Berichte, Zusammenfassungsdiagramme und geplante zukünftige Transaktionen erstellt habe, aber ... ich war schnell müde von allem.

Warum ist es unpraktisch, das Journal eines Händlers manuell zu führen?
  • Das manuelle Ausfüllen des Journals (auch bei teilweiser Automatisierung in Form des Entladens der täglichen Transaktionen vom Handelsterminal) wird schnell müde.
  • Bei manueller Eingabe besteht ein hohes Risiko für Fehler oder Tippfehler.
  • Es kann vorkommen, dass ein aktiver Händler ein passiver Investor wird und immer weniger auf dieses Magazin zurückkommt und es dann völlig vergisst (mein Fall). gut und endlich
  • wir können programmieren, warum nicht nutzen und den gesamten Prozess automatisieren? Also, lass uns gehen!

Maklerunternehmen sind häufig High-Tech-Unternehmen, die ihren Kunden qualitativ hochwertige Analysen zu fast allen interessanten Themen liefern. Man kann mit Recht sagen, dass diese Berichterstattung mit jedem Update immer besser wird, aber selbst die fortgeschrittensten von ihnen verfügen möglicherweise nicht über die Anpassung und Konsolidierung, die anspruchsvolle und neugierige Kunden sehen möchten.

Mit Opening Broker können Sie beispielsweise Brokerage-Berichte im XML-Format in Ihrem persönlichen Konto empfangen. Wenn Sie jedoch über ein IIA- und ein reguläres Brokerage-Konto an der Moskauer Börse (MOEX) verfügen, handelt es sich um zwei verschiedene Berichte. Wenn Sie ein anderes Konto bei St. Petersburg Stock Exchange (SPB), dann werden die ersten beiden eine weitere hinzufügen.

Um ein konsolidiertes Journal des Investors zu erhalten, müssen insgesamt drei Dateien im XML-Format verarbeitet werden.

Die oben genannten Berichte zu MOEX und SPB unterscheiden sich geringfügig in ihren Formaten, die bei der Implementierung der Datenzuordnung berücksichtigt werden müssen.

Architektur des in Entwicklung befindlichen Systems


Das folgende Diagramm zeigt das Architekturmodell des in Entwicklung befindlichen Systems:


Parser-Implementierung


Wir erhalten Berichte über alle drei Konten im persönlichen Konto für den maximal möglichen Zeitraum (kann in mehrere Berichte für jedes Jahr unterteilt werden), speichern sie im XML-Format und legen sie in einem Ordner ab. Als Testdaten für die Studie werden wir ein fiktives Kundenportfolio verwenden, dessen Parameter jedoch den Marktrealitäten so nahe wie möglich kommen.


Angenommen, der betreffende Investor Mr. X verfügt über ein kleines Portfolio von fünf Wertpapieren:

  1. Der Bericht über die SPB-Börse wird zwei Papiere enthalten: Apple und Microsoft;
  2. Der Bericht über die MOEX-Börse (Brokerage) enthält ein Papier: FGC UES;
  3. Der Bericht an der MOEX Exchange (IIS) enthält zwei Wertpapiere: MMK und OFZ 24019;

Gemäß unseren fünf Wertpapieren kann es zu Transaktionen beim Kauf / Verkauf, bei der Zahlung von Dividenden und Coupons, bei Preisänderungen usw. kommen. Wir wollen die aktuelle Situation sehen, nämlich: das Finanzergebnis unter Berücksichtigung aller Zahlungen, Transaktionen und des aktuellen Marktwerts.

Und hier kommt Python ins Spiel, wir lesen Informationen aus allen Berichten in einem Array:

my_files_list = [join('Data/', f) for f in listdir('Data/') if isfile(join('Data/', f))] my_xml_data = [] #     for f in my_files_list: tree = ET.parse(f) root = tree.getroot() my_xml_data.append(root) 

Für die Analyse benötigen wir aus den Berichten mehrere Entitäten, nämlich:

  • Positionen von Wertpapieren in einem Portfolio;
  • Abgeschlossene Geschäfte;
  • Nichthandelsgeschäfte und andere Kontobewegungen;
  • Durchschnittspreise offener Positionen
Um das Beispiel vorzubereiten, werden wir vier Wörterbücher verwenden, um die obigen Sätze zu beschreiben.

 dict_stocks = {'stock_name': [], 'account': [], 'currency': [], 'current_cost': [], 'current_cost_rub': [], 'saldo' : []} dict_deals = {'stock_name': [], 'account': [], 'date_oper': [], 'type_oper': [], 'quantity': [], 'price': [], 'currency': [], 'brokerage': [], 'result': []} dict_flows = {'stock_name': [], 'account': [], 'date_oper': [], 'type_oper': [], 'result': [], 'currency': []} dict_avg_price = {'stock_name': [], 'account': [], 'avg_open_price' : []} 

Ein paar Worte darüber, worum es in diesen Wörterbüchern geht.

Dict_stocks Wörterbuch
Das Wörterbuch dict_stocks wird benötigt, um allgemeine Informationen zum Portfolio zu speichern:

  • Name des Papiers (stock_name);
  • Name des Kontos (SPB, MOEX BROK, MOEX IIS) (Konto);
  • Währung, die für Abrechnungen auf diesem Papier verwendet wird (Währung);
  • Aktueller Wert (zum Zeitpunkt der Erstellung des Berichts im Eröffnungsmakler für persönliche Konten) (current_cost). An dieser Stelle möchte ich darauf hinweisen, dass es für anspruchsvolle Kunden möglich ist, in Zukunft weitere Verbesserungen vorzunehmen und den dynamischen Empfang eines Sicherheitsangebots von einem Handelsterminal oder von der Website der entsprechenden Börse zu verwenden.
  • Der aktuelle Wert der Sicherheitsposition zum Zeitpunkt der Berichterstellung (current_cost_rub)
    Ähnlich wie oben können Sie hier auch den aktuellen Wechselkurs der Zentralbank oder den Wechselkurs nach Belieben abrufen.
  • Aktueller Wertpapierbestand (saldo)

Wörterbuch dict_deals
Das Wörterbuch dict_deals ist erforderlich, um die folgenden Informationen zu abgeschlossenen Transaktionen zu speichern:

  • Name des Papiers (stock_name);
  • Name des Kontos (SPB, MOEX BROK, MOEX IIS) (Konto);
  • Datum der Transaktion, d.h. T0 (date_oper);
  • Art der Operation (type_oper);
  • Das Volumen der an der Transaktion beteiligten Wertpapiere (Menge);
  • Der Preis, zu dem die Transaktion ausgeführt wurde (Preis);
  • Währung, in der die Transaktion durchgeführt wurde (Währung);
  • Maklerprovision für eine Transaktion (Maklergebühr);
  • Das finanzielle Ergebnis der Transaktion (Ergebnis)

Dict_flows Wörterbuch
Das Wörterbuch dict_flows spiegelt die Bewegung von Geldern auf dem Kundenkonto wider und wird zum Speichern der folgenden Informationen verwendet:

  • Name des Papiers (stock_name);
  • Name des Kontos (SPB, MOEX BROK, MOEX IIS) (Konto);
  • Datum der Transaktion, d.h. T0 (date_oper);
  • Art der Operation (type_oper). Es kann mehrere Werte annehmen: div, NKD, tax;
  • Währung, in der die Transaktion durchgeführt wurde (Währung);
  • Das finanzielle Ergebnis der Operation (Ergebnis)

Wörterbuch dict_avg_price
Das Wörterbuch dict_avg_price ist für Buchhaltungsinformationen zum durchschnittlichen Kaufpreis für jedes Papier erforderlich:

  • Name des Papiers (stock_name);
  • Name des Kontos (SPB, MOEX BROK, MOEX IIS) (Konto);
  • Durchschnittspreis einer offenen Position (avg_open_price)

Wir verarbeiten eine Reihe von XML-Dokumenten und füllen diese Wörterbücher mit den entsprechenden Daten aus:

 #       for XMLdata in my_xml_data: #      exchange_name = 'SPB' if XMLdata.get('board_list') == ' ' else 'MOEX' client_code = XMLdata.get('client_code') account_name = get_account_name(exchange_name, client_code) #   current_position, deals, flows, stock_name, \ saldo, ticketdate, price, brokerage, \ operationdate, currency, \ current_cost, current_cost_rub, \ stock_name_deal, payment_currency, currency_flows = get_allias(exchange_name) #      get_briefcase(XMLdata) df_stocks = pd.DataFrame(dict_stocks) df_stocks.set_index("stock_name", drop = False, inplace = True) #    get_deals(XMLdata) df_deals = pd.DataFrame(dict_deals) df_avg = pd.DataFrame(dict_avg_price) #       get_nontrade_operation(XMLdata) df_flows = pd.DataFrame(dict_flows) 

Die gesamte Verarbeitung durchläuft die Schleife aller XML-Daten aus den Berichten. Informationen zur Handelsplattform und zum Client-Code sind in allen Berichten gleich, sodass Sie ihn ohne Zuordnung sicher aus denselben Tags extrahieren können.

Aber dann müssen wir ein spezielles Design verwenden, das den erforderlichen Alias ​​für das Tag basierend auf dem Bericht (SPB oder MOEX) bereitstellt, weil Identische Daten in diesen Berichten werden unterschiedlich bezeichnet.

Tag-Diskrepanzen
  • Die Transaktionsbroker-Provision im SBP-Bericht liegt im Brokerage- Tag und im MOEX-Report - broker_commission ;
  • Das Transaktionsdatum des Nichthandelskontos im SPB-Bericht ist das Betriebsdatum und in MOEX das Betriebsdatum usw.

Beispiel für die Tag-Zuordnung
 tags_mapping = { 'SPB': { 'current_position': 'briefcase_position', 'deals': 'closed_deal', 'flows': 'nontrade_money_operation', ... 'stock_name_deal': 'issuername', 'paymentcurrency': 'paymentcurrency', 'currency_flows': 'currencycode' }, 'MOEX': { 'current_position': 'spot_assets', 'deals': 'spot_main_deals_conclusion', 'flows': 'spot_non_trade_money_operations', ... 'stock_name_deal': 'security_name', 'paymentcurrency': 'price_currency_code', 'currency_flows': 'currency_code' } } 

Die Funktion get_allias gibt den Namen des für die Verarbeitung erforderlichen Tags zurück und nimmt den Namen der Handelsplattform als Eingabe:

Get_allias-Funktion
 def get_allias(exchange_name): return( tags_mapping[exchange_name]['current_position'], tags_mapping[exchange_name]['deals'], tags_mapping[exchange_name]['flows'], ... tags_mapping[exchange_name]['stock_name_deal'], tags_mapping[exchange_name]['paymentcurrency'], tags_mapping[exchange_name]['currency_flows'] ) 

Die Funktion get_briefcase ist für die Verarbeitung von Informationen zum Status des Kundenportfolios verantwortlich:

Get_briefcase-Funktion
 def get_briefcase(XMLdata): #         briefcase_position briefcase_position = XMLdata.find(current_position) if not briefcase_position: return try: for child in briefcase_position: stock_name_reduce = child.get(stock_name).upper() stock_name_reduce = re.sub('[,\.]|(\s?INC)|(\s+$)|([-\s]?)', '', stock_name_reduce) dict_stocks['stock_name'].append(stock_name_reduce) dict_stocks['account'].append(account_name) dict_stocks['currency'].append(child.get(currency)) dict_stocks['current_cost'].append(float(child.get(current_cost))) dict_stocks['current_cost_rub'].append(float(child.get(current_cost_rub))) dict_stocks['saldo'].append(float(child.get(saldo))) except Exception as e: print('get_briefcase --> Oops! It seems we have a BUG!', e) 

Als Nächstes ruft die Funktion get_deals Informationen zu Transaktionen ab:

Get_deals-Funktion
 def get_deals(XMLdata): stock_name_proc = '' closed_deal = XMLdata.find(deals) if not closed_deal: return #   SPB    -    , #    MOEX:  ,      #    : if exchange_name == 'SPB': sortchildrenby(closed_deal, stock_name_deal) for child in closed_deal: sortchildrenby(child, stock_name_deal) try: for child in closed_deal: stock_name_reduce = child.get(stock_name_deal).upper() stock_name_reduce = re.sub('[,\.]|(\s?INC)|(\s+$)|([-\s]?)', '', stock_name_reduce) dict_deals['stock_name'].append(stock_name_reduce) dict_deals['account'].append(account_name) dict_deals['date_oper'].append(to_dt(child.get(ticketdate)).strftime('%Y-%m-%d')) current_cost = get_current_cost(stock_name_reduce) #    SPB     - quantity, #   MOEX  : buy_qnty  sell_qnty if exchange_name == 'MOEX': if child.get('buy_qnty'): quantity = float(child.get('buy_qnty')) else: quantity = - float(child.get('sell_qnty')) else: quantity = float(child.get('quantity')) dict_deals['quantity'].append(quantity) dict_deals['price'].append(float(child.get('price'))) dict_deals['type_oper'].append('deal') dict_deals['currency'].append(child.get(payment_currency)) brok_comm = child.get(brokerage) if brok_comm is None: brok_comm = 0 else: brok_comm = float(brok_comm) dict_deals['brokerage'].append(float(brok_comm)) #         if stock_name_proc != stock_name_reduce: if stock_name_proc != '': put_avr_price_in_df(account_name, stock_name_proc, \ pnl.m_net_position, pnl.m_avg_open_price) current_cost = get_current_cost(stock_name_proc) pnl.update_by_marketdata(current_cost) if len(dict_deals['result']) > 0: if exchange_name != 'SPB': dict_deals['result'][-1] = pnl.m_unrealized_pnl * 0.87 -dict_deals['brokerage'][-2] else: dict_deals['result'][-1] = pnl.m_unrealized_pnl - dict_deals['brokerage'][-2] stock_name_proc = stock_name_reduce pnl = PnlSnapshot(stock_name_proc, float(child.get('price')), quantity) dict_deals['result'].append(-1 * brok_comm) else: pnl.update_by_tradefeed(float(child.get('price')), quantity) #  ,   if quantity < 0: if pnl.m_realized_pnl > 0 and exchange_name != 'SPB': pnl_sum = pnl.m_realized_pnl * 0.87 - brok_comm else: pnl_sum = pnl.m_realized_pnl - brok_comm dict_deals['result'].append(float(pnl_sum)) else: pnl.update_by_marketdata(current_cost) dict_deals['result'].append(-1 * brok_comm) put_avr_price_in_df(account_name, stock_name_proc, \ pnl.m_net_position, pnl.m_avg_open_price) current_cost = get_current_cost(stock_name_proc) pnl.update_by_marketdata(current_cost) if len(dict_deals['result']) > 0: if exchange_name != 'SPB': dict_deals['result'][-1] = pnl.m_unrealized_pnl * 0.87 -dict_deals['brokerage'][-2] else: dict_deals['result'][-1] = pnl.m_unrealized_pnl - dict_deals['brokerage'][-2] except Exception as e: print('get_deals --> Oops! It seems we have a BUG!', e) 

Neben der Verarbeitung eines Arrays mit Informationen zu den Parametern der Transaktion wird hier auch der Durchschnittspreis einer offenen Position berechnet, der von PNL unter Verwendung der FIFO-Methode realisiert wird. Die PnlSnapshot-Klasse ist für diese Berechnung verantwortlich, für deren Erstellung mit den kleinen Änderungen der hier dargestellte Code als Grundlage verwendet wurde: GuV-Berechnung

Am schwierigsten zu implementieren ist schließlich die Funktion, Informationen über nicht handelsbezogene Vorgänge zu erhalten - get_nontrade_operation . Seine Komplexität liegt in der Tatsache, dass im Berichtsblock, der für nicht handelsbezogene Vorgänge verwendet wird, keine eindeutigen Informationen über die Art der Transaktion und die Sicherheit vorhanden sind, an die dieser Vorgang gebunden ist.

Beispiel für Zahlungsziele für Nichthandelsgeschäfte
Die Zahlung von Dividenden oder kumulierten Couponeinnahmen kann wie folgt angegeben werden:

  1. Zahlung von Dividenden des Einkommenskunden <777777> < APPLE INC-ao> -> Zahlung von Dividenden aus dem SPB-Bericht;
  2. Zahlung von Dividenden des Kunden <777777> < MICROSOFT COM->
  3. Zahlung des Kundeneinkommens 777777i (NKD 2 OFZ 24019 ) Quellensteuer 0,00 Rubel -> Couponzahlung aus dem MOEX-Bericht;
  4. Zahlung von Erträgen an den Kunden 777777 Dividenden von FGC UES - eine Quellensteuer XX.XX Rubel -> Zahlung von Dividenden aus dem MOEX-Bericht. usw.

Dementsprechend wird es schwierig sein, auf reguläre Ausdrücke zu verzichten, daher werden wir sie in vollem Umfang nutzen. Die andere Seite des Problems ist, dass der Name des Unternehmens nicht immer mit dem Namen im Portfolio oder bei Transaktionen zum Zweck der Zahlung übereinstimmt. Daher muss der vom Zahlungszweck erhaltene Name des Emittenten zusätzlich mit dem Wörterbuch korreliert werden. Als Wörterbuch werden wir eine Reihe von Angeboten verwenden, weil Es gibt die vollständigste Liste der Unternehmen.

Die Funktion get_company_from_str ruft den Namen des Ausstellers aus dem Kommentar ab:

Get_company_from_str Funktion
 def get_company_from_str(comment): company_name = '' #    / flows_pattern = [ '^.+\s<(\w+)?.+->$', '^.+\s(.+)-.+$', '^.+\(\s\d?\s(.+)\).+$', '^.+\s(.+)-.+$' ] for pattern in flows_pattern: match = re.search(pattern, comment) if match: return match.group(1).upper() return company_name 

Die Funktion get_company_from_briefcase führt den Firmennamen zum Wörterbuch, wenn eine Übereinstimmung zwischen den an den Transaktionen beteiligten Unternehmen gefunden wird:

Get_company_from_briefcase-Funktion
 def get_company_from_briefcase(company_name): company_name_full = None value_from_dic = df_deals[df_deals['stock_name'].str.contains(company_name)] company_arr = value_from_dic['stock_name'].unique() if len(company_arr) == 1: company_name_full = company_arr[0] return company_name_full 


Und schließlich ist die letzte Funktion des Sammelns von Daten über Nichthandelsvorgänge get_nontrade_operation :

Get_nontrade_operation Funktion
 def get_nontrade_operation(XMLdata): nontrade_money_operation = XMLdata.find(flows) if not nontrade_money_operation: return try: for child in nontrade_money_operation: comment = child.get('comment') type_oper_match = re.search('||^.+.+.+$', comment) if type_oper_match: company_name = get_company_from_str(comment) type_oper = get_type_oper(comment) dict_flows['stock_name'].append(company_name) dict_flows['account'].append(account_name) dict_flows['date_oper'].append(to_dt(child.get(operationdate)).strftime('%Y-%m-%d')) dict_flows['type_oper'].append(type_oper) dict_flows['result'].append(float(child.get('amount'))) dict_flows['currency'].append(child.get(currency_flows)) except Exception as e: print('get_nontrade_operation --> Oops! It seems we have a BUG!', e) 

Das Ergebnis der Datenerfassung aus Berichten sind drei DataFrames, die ungefähr die folgenden sind:

  1. DataFrame mit Informationen zu Durchschnittspreisen offener Positionen:
  2. Deal DataFrame:
  3. DataFrame mit Informationen zu nicht handelsbezogenen Vorgängen:


Wir müssen also nur noch eine externe Vereinigung der Transaktionstabelle mit der Portfolio-Informationstabelle durchführen:

 df_result = pd.merge(df_deals, df_stocks_avg, how='outer', on=['stock_name', 'account', 'currency']).fillna(0) df_result.sample(10) 


Und schließlich ist der letzte Teil der Verarbeitung des Datenarrays das Zusammenführen des im vorherigen Schritt erhaltenen Datenarrays mit dem DataFrame für nicht handelbare Transaktionen.
Das Ergebnis der geleisteten Arbeit ist ein großer flacher Tisch mit allen für die Analyse erforderlichen Informationen:

 df_result_full = df_result.append(df_flows, ignore_index=True).fillna(0) df_result_full.sample(10).head() 


Der resultierende Datensatz (Abschlussbericht) aus dem DataFrame kann problemlos in die CSV hochgeladen werden und kann dann für detaillierte Analysen in jedem BI-System verwendet werden.

 if not exists('OUTPUT'): makedirs('OUTPUT') report_name = 'OUTPUT\my_trader_diary.csv' df_result_full.to_csv(report_name, index = False, encoding='utf-8-sig') 


Daten in AWS hochladen und verarbeiten


Der Fortschritt steht nicht still und jetzt gewinnen Cloud-Dienste und Serverless-Computing-Modelle bei der Datenverarbeitung und -speicherung an Popularität. Dies liegt hauptsächlich an der Einfachheit und Billigkeit dieses Ansatzes, wenn Sie keine teuren Geräte kaufen müssen, um eine Systemarchitektur für komplexe Computer oder die Verarbeitung von Big Data zu erstellen, sondern nur die Leistung in der Cloud für die benötigte Zeit mieten und die erforderlichen Ressourcen schnell genug für eine relativ geringe Gebühr bereitstellen .

Einer der größten und bekanntesten Cloud-Anbieter auf dem Markt ist Amazon. Schauen wir uns das Beispiel der Amazon Web Services (AWS) -Umgebung an, um ein Analysesystem für die Verarbeitung von Daten in unserem Anlageportfolio zu erstellen.

AWS verfügt über eine umfangreiche Auswahl an Tools, wir werden jedoch Folgendes verwenden:

  • Amazon S3 - Objektspeicher, mit dem Sie nahezu unbegrenzt viele Informationen speichern können;
  • AWS Glue - der leistungsstärkste Cloud-ETL-Service, der selbst die Struktur bestimmen und den ETL-Code aus den angegebenen Quelldaten generieren kann.
  • Mit Amazon Athena , einem serverlosen Online-SQL-Abfragedienst, können Sie Daten aus S3 ohne große Vorbereitung schnell analysieren. Er hat auch Zugriff auf die Metadaten, die AWS Glue erstellt, sodass Sie unmittelbar nach dem Übergeben der ETL auf die Daten zugreifen können.
  • Amazon QuickSight - Serverloser BI-Service, mit dem Sie Visualisierungen, Analyseberichte "on the fly" usw. erstellen können.

Die Dokumentation von Amazon ist in Ordnung, insbesondere gibt es einen guten Artikel Best Practices bei der Verwendung von Athena mit AWS Glue , in dem beschrieben wird, wie Tabellen und Daten mit AWS Glue erstellt und verwendet werden. Lassen Sie uns die Hauptideen dieses Artikels nutzen und sie anwenden, um unsere eigene Architektur eines analytischen Berichtssystems zu erstellen.

Die von unserem Berichtsparser erstellten CSV-Dateien werden dem S3-Bucket hinzugefügt. Es ist geplant, dass der entsprechende Ordner in S3 jeden Samstag - am Ende der Handelswoche - aufgefüllt wird, sodass Sie nicht auf eine Datenpartitionierung bis zum Datum der Erstellung und Verarbeitung des Berichts verzichten können.
Dieser Ansatz optimiert nicht nur den Betrieb von SQL-Abfragen für solche Daten, sondern ermöglicht es uns auch, zusätzliche Analysen durchzuführen, um beispielsweise die Dynamik von Änderungen im Finanzergebnis für jedes Papier usw. zu ermitteln.

Arbeiten Sie mit Amazon S3
  • Erstellen Sie einen Bucket in S3 und nennen Sie ihn "Report-Parser".
  • Erstellen Sie in diesem Bucket "report-parser" einen Ordner mit dem Namen "my_trader_diary".
  • Erstellen Sie im Verzeichnis "my_trader_diary" ein Verzeichnis mit dem Datum des aktuellen Berichts, z. B. "date_report = 2018-10-01", und legen Sie die CSV-Datei darin ab.
  • Nur zum Zwecke des Experiments und zum besseren Verständnis der Partitionierung werden zwei weitere Verzeichnisse erstellt: "date_report = 2018-09-27" und "date_report = 2018-10-08". Wir haben dieselbe CSV-Datei in sie eingefügt.
  • Der endgültige S3-Bucket "Report-Parser" sollte wie in den folgenden Bildern gezeigt aussehen:


Arbeiten Sie mit AWS Glue
Im Großen und Ganzen können Sie nur mit Amazon Athena eine externe Tabelle aus den auf S3 liegenden Daten erstellen. AWS Glue ist hierfür jedoch ein flexibleres und praktischeres Tool.

  • Wir gehen in AWS Glue und erstellen einen neuen Crawler, der eine Tabelle aus separaten CSV-Dateien nach Berichtsdaten sammelt:
    • Legen Sie den Namen des neuen Crawlers fest.
    • Wir geben das Repository an, von dem die Daten abgerufen werden sollen (s3: // report-parser / my_trader_diary /)
    • Wir wählen oder erstellen eine neue IAM-Rolle, die Zugriff zum Starten von Crawler und Zugriff auf die angegebene Ressource in S3 hat.
    • Als nächstes müssen Sie die Startfrequenz einstellen. Wir stellen es vorerst auf Anfrage ein, aber ich denke, dass sich dies in Zukunft ändern wird und der Start wöchentlich erfolgt.
    • Speichern Sie und warten Sie, bis der Crawler erstellt wurde.
  • Wenn der Crawler in den Bereitschaftszustand wechselt, starten Sie ihn!

  • Sobald es funktioniert, wird eine neue my_trader_diary-Tabelle auf der Registerkarte AWS Glue: Database -> Tables angezeigt:


Betrachten Sie die generierte Tabelle genauer.
Wenn Sie auf den Namen der erstellten Tabelle klicken, gelangen Sie zur Seite mit der Beschreibung der Metadaten. Unten befindet sich ein Tabellenlayout und das neueste ist eine Spalte, die nicht in der CSV-Quelldatei enthalten war - date_report. Diese Spalte wird von AWS Glue automatisch basierend auf der Definition von Abschnitten der Quelldaten erstellt (in Bucket S3 haben wir die Ordner date_report = YYYY-MM-DD speziell benannt, sodass wir sie als nach Datum getrennte Abschnitte verwenden konnten).

Tabellenpartitionierung

Auf derselben Seite in der oberen rechten Ecke befindet sich eine Schaltfläche Partitionen anzeigen. Klicken Sie auf, um zu sehen, aus welchen Abschnitten unsere generierte Tabelle besteht:

Datenanalyse


Nachdem wir verarbeitete Daten hochgeladen haben, können wir diese leicht analysieren. Betrachten Sie zunächst die Funktionen von Amazon Athena als die einfachste und schnellste Möglichkeit, analytische Abfragen durchzuführen. Gehen Sie dazu zum Amazon Athena-Dienst, wählen Sie die benötigte (finanzielle) Datenbank aus und schreiben Sie den folgenden SQL-Code:

 select d.date_report, d.account, d.stock_name, d.currency, sum(d.quantity) as quantity, round(sum(d.result), 2) as result from my_trader_diary d group by d.date_report, d.account, d.stock_name, d.currency order by d.account, d.stock_name, d.date_report; 

Diese Anfrage zeigt uns ein Nettofinanzergebnis für jedes Wertpapier für alle Berichtsdaten. Weil Wir haben denselben Bericht dreimal für unterschiedliche Daten heruntergeladen. Das Ergebnis wird sich nicht ändern, was in einem realen Markt natürlich anders sein wird:


Was aber, wenn wir die empfangenen Daten in Form flexibler Tabellen oder Diagramme visualisieren wollen? Hier hilft Amazon QuickSight, mit dessen Hilfe Sie flexible Analysen fast so schnell konfigurieren können wie das Schreiben einer SQL-Abfrage. Wir rufen den Amazon QuickSight-Dienst auf (wenn Sie sich dort nicht registriert haben, ist eine Registrierung erforderlich).

Klicken Sie auf die Schaltfläche Neue Analysen -> Neuer Datensatz und klicken Sie im angezeigten Fenster auf Quellen für den Datensatz, klicken Sie auf Athena:



Wir werden einen Namen für unsere Datenquelle finden, zum Beispiel "PNL_analysis" und auf die Schaltfläche "Datenquelle erstellen" klicken.

Als Nächstes wird das Fenster "Tabelle auswählen" geöffnet, in dem Sie die Datenbank und die Datenquellentabelle auswählen müssen. Wir wählen die Datenbank - finanziell und die Tabelle darin aus: my_traider_diary. Standardmäßig wird die gesamte Tabelle verwendet. Wenn Sie jedoch "Benutzerdefiniertes SQL verwenden" auswählen, können Sie das benötigte Datenbeispiel anpassen und optimieren. Zum Beispiel verwenden wir die gesamte Tabelle und klicken auf die Schaltfläche Daten bearbeiten / Vorschau.

Eine neue Seite wird geöffnet, auf der Sie zusätzliche Einstellungen vornehmen und vorhandene Daten verarbeiten können.

Jetzt müssen wir unserem Datensatz zusätzliche berechnete Felder hinzufügen: Quartal und Betriebsjahr. Ein aufmerksamer Leser kann feststellen, dass solche Manipulationen auf der Parser-Seite einfacher durchzuführen waren, bevor der Abschlussbericht in CSV gespeichert wurde. Zweifellos ist es jetzt mein Ziel, die Fähigkeiten und die Flexibilität der BI-Systemeinstellungen im laufenden Betrieb zu demonstrieren. Wir erstellen weiterhin berechnete Felder, indem wir auf die Schaltfläche "Neues Feld" klicken.

Erstellen Sie ein neues Feld

Um das Jahr der Operation und das Quartal hervorzuheben, werden einfache Formeln verwendet:


Formeln für ein neues Feld ausfüllen

Wenn die berechneten Felder erfolgreich erstellt und zur Auswahl hinzugefügt wurden, geben Sie unserem Datensatz einen Namen, z. B. "my_pnl_analyze", und klicken Sie auf die Schaltfläche "Speichern und visualisieren".

Danach übertragen wir auf die Amazon QuickSight-Hauptplatine. Als erstes müssen wir einen Filter für das Berichtsdatum einrichten (unter Berücksichtigung der Tatsache, dass dieselben Daten aus drei Abschnitten erfasst wurden). Wählen Sie das Berichtsdatum 2018-10-01 aus, klicken Sie auf die Schaltfläche Übernehmen und wechseln Sie zur Registerkarte Visualisieren.

Filtereinstellung

, , , (.. ) . BI – . , ( MS Excel)

, , , .. 1 509.91 . (1 763.36 . – 174 . – ). .

– :


, , , . : sum_investment count_days.

sum_investment
sum_investment ( ) :

ifelse({stock_name} = ' 24019',{avg_open_price} * quantity * 10,{avg_open_price} * quantity)

, – ( – 1000).

count_days
count_day ( ) :

dateDiff(parseDate({date_oper}),parseDate({date_report}))

:




« » Amazon. , .. , , , .

, ( ) . , , , – .

, . , PNL (, ), .… Quicksight , , Python .

- , : XML-! , , API . Amazon: ETL-job AWS Glue Amazon QuickSight .

GitHub

Source: https://habr.com/ru/post/de426027/


All Articles