diff --git a/migrations/0002_trade.py b/migrations/0002_trade.py new file mode 100644 index 0000000..b41df9b --- /dev/null +++ b/migrations/0002_trade.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.6 on 2017-03-06 14:17 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dashboard', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Trade', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('account', models.CharField(max_length=256)), + ('security', models.CharField(max_length=256)), + ('price', models.DecimalField(decimal_places=10, max_digits=20)), + ('quantity', models.IntegerField()), + ('volume', models.DecimalField(decimal_places=10, max_digits=25)), + ('volumeCurrency', models.CharField(max_length=10)), + ('strategyId', models.CharField(max_length=64)), + ('signalId', models.CharField(max_length=64)), + ('comment', models.CharField(max_length=256)), + ('timestamp', models.DateTimeField()), + ('balanced', models.BooleanField(default=False)), + ], + ), + ] diff --git a/models.py b/models.py index cbece3c..d948642 100644 --- a/models.py +++ b/models.py @@ -2,3 +2,17 @@ from django.db import models class RobotInstance(models.Model): instanceId = models.CharField(max_length=255) + +class Trade(models.Model): + account = models.CharField(max_length=256) + security = models.CharField(max_length=256) + price = models.DecimalField(max_digits=20, decimal_places=10) + quantity = models.IntegerField() + volume = models.DecimalField(max_digits=25, decimal_places=10) + volumeCurrency = models.CharField(max_length=10) + strategyId = models.CharField(max_length=64) + signalId = models.CharField(max_length=64) + comment = models.CharField(max_length=256) + timestamp = models.DateTimeField() + balanced = models.BooleanField(default=False) + diff --git a/templates/dashboard/base.html b/templates/dashboard/base.html index bd84c32..6418644 100644 --- a/templates/dashboard/base.html +++ b/templates/dashboard/base.html @@ -16,6 +16,7 @@ diff --git a/templates/dashboard/trades.html b/templates/dashboard/trades.html new file mode 100644 index 0000000..de9287f --- /dev/null +++ b/templates/dashboard/trades.html @@ -0,0 +1,33 @@ +{% extends "dashboard/base.html" %} +{% load mathfilters %} + +{% block content %} + + + + + + + + + + + + + +{% for trade in trades %} + + + + + + + + + + + + +{% endfor %} +
TimeAccountSecurityOperationPriceQuantityVolumeStrategy IDSignal ID
{{ trade.timestamp }}{{ trade.account }}{{ trade.security }}{% if trade.quantity > 0 %} Buy {% else %} Sell {% endif %}{{ trade.price }}{{ trade.quantity|abs }}{{ trade.volume|stringformat:".3f"}} {{ trade.volumeCurrency }}{{ trade.strategyId }}{{ trade.signalId }}
+{% endblock %} diff --git a/tradesink.py b/tradesink.py new file mode 100644 index 0000000..5564875 --- /dev/null +++ b/tradesink.py @@ -0,0 +1,55 @@ +import os +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "atrade_dashboard.settings") +import django +django.setup() + +import zmq +import argparse +import datetime +from dashboard.models import Trade + +def parse_timestamp(ts): + return datetime.datetime.strptime(ts, '%Y-%m-%d %H:%M:%S.%f') + +def store_trade(j): + quantity = int(j['quantity']) + if j['operation'] == 'sell': + quantity = -quantity + elif j['operation'] != 'buy': + raise Exception('Invalid operation: ' + j['operation']) + ts = parse_timestamp(j['execution-time']) + trade = Trade(account=j['account'], security=j['security'], price=float(j['price']), quantity=quantity, volume=float(j['volume']), volumeCurrency=j['volume-currency'], strategyId=j['strategy'], + signalId=j['signal-id'], comment=j['order-comment'], timestamp=ts) + trade.save() + + +def handle_cmd(cmd): + try: + if 'command' in cmd.keys(): + return { 'response' : 'ok' } + elif 'trade' in cmd.keys(): + store_trade(cmd['trade']) + return { 'response' : 'ok' } + except Exception as e: + print(e) + return { 'response' : 'error' } + +def main(): + parser = argparse.ArgumentParser(description='Trade sink process') + parser.add_argument('-e', '--endpoint', action='store', help='Trade sink endpoint') + args = parser.parse_args() + + ctx = zmq.Context.instance() + s = ctx.socket(zmq.REP) + s.bind(args.endpoint) + + while True: + events = s.poll(1000, zmq.POLLIN) + if events == zmq.POLLIN: + cmd = s.recv_json() + response = handle_cmd(cmd) + s.send_json(response) + + +if __name__ == "__main__": + main() diff --git a/urls.py b/urls.py index 71fb116..3f307eb 100644 --- a/urls.py +++ b/urls.py @@ -7,5 +7,6 @@ urlpatterns = [ url(r'^$', views.overview, name='overview'), url(r'^add_instance$', views.add_instance, name='add_instance'), url(r'^delete_instance/(?P[^/]+)$', views.delete_instance, name='delete_instance'), + url(r'^trades/$', views.trades_index, name='trades_index'), ] diff --git a/views.py b/views.py index dfcd752..9bba457 100644 --- a/views.py +++ b/views.py @@ -5,7 +5,7 @@ from django.shortcuts import render, get_object_or_404 from django.urls import reverse from django.contrib import messages -from .models import RobotInstance +from .models import RobotInstance, Trade import redis import json import datetime @@ -70,3 +70,10 @@ def delete_instance(request, instance_id): instance.delete() return HttpResponseRedirect(reverse('overview')) +def trades_index(request): + trades = Trade.objects.all() + template = loader.get_template('dashboard/trades.html') + context = { + 'trades' : trades + } + return HttpResponse(template.render(context, request))