7 changed files with 144 additions and 1 deletions
@ -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)), |
||||||
|
], |
||||||
|
), |
||||||
|
] |
||||||
@ -0,0 +1,33 @@ |
|||||||
|
{% extends "dashboard/base.html" %} |
||||||
|
{% load mathfilters %} |
||||||
|
|
||||||
|
{% block content %} |
||||||
|
<table class="table table-condensed"> |
||||||
|
<tr> |
||||||
|
<td>Time</td> |
||||||
|
<td>Account</td> |
||||||
|
<td>Security</td> |
||||||
|
<td>Operation</td> |
||||||
|
<td>Price</td> |
||||||
|
<td>Quantity</td> |
||||||
|
<td>Volume</td> |
||||||
|
<td>Strategy ID</td> |
||||||
|
<td>Signal ID</td> |
||||||
|
<td></td> |
||||||
|
</tr> |
||||||
|
{% for trade in trades %} |
||||||
|
<tr> |
||||||
|
<td>{{ trade.timestamp }}</td> |
||||||
|
<td>{{ trade.account }}</td> |
||||||
|
<td>{{ trade.security }}</td> |
||||||
|
<td>{% if trade.quantity > 0 %} Buy {% else %} Sell {% endif %}</td> |
||||||
|
<td>{{ trade.price }}</td> |
||||||
|
<td>{{ trade.quantity|abs }}</td> |
||||||
|
<td>{{ trade.volume|stringformat:".3f"}} {{ trade.volumeCurrency }}</td> |
||||||
|
<td>{{ trade.strategyId }}</td> |
||||||
|
<td>{{ trade.signalId }}</td> |
||||||
|
<td><button type="button" class="btn btn-danger" onclick="if(window.confirm('Confirm deletion')) { document.location.href = '/delete_trade?id={{ trade.pk }}'}; return false;">Delete</button></td> |
||||||
|
</tr> |
||||||
|
{% endfor %} |
||||||
|
</table> |
||||||
|
{% endblock %} |
||||||
@ -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() |
||||||
Loading…
Reference in new issue