commit
5d3c657a71
12 changed files with 188 additions and 0 deletions
@ -0,0 +1,3 @@ |
|||||||
|
from django.contrib import admin |
||||||
|
|
||||||
|
# Register your models here. |
||||||
@ -0,0 +1,5 @@ |
|||||||
|
from django.apps import AppConfig |
||||||
|
|
||||||
|
|
||||||
|
class DashboardConfig(AppConfig): |
||||||
|
name = 'dashboard' |
||||||
@ -0,0 +1,23 @@ |
|||||||
|
# -*- coding: utf-8 -*- |
||||||
|
# Generated by Django 1.10.6 on 2017-03-04 23:52 |
||||||
|
from __future__ import unicode_literals |
||||||
|
|
||||||
|
from django.db import migrations, models |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
initial = True |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.CreateModel( |
||||||
|
name='RobotInstance', |
||||||
|
fields=[ |
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||||
|
('instanceId', models.CharField(max_length=255)), |
||||||
|
], |
||||||
|
), |
||||||
|
] |
||||||
@ -0,0 +1,4 @@ |
|||||||
|
from django.db import models |
||||||
|
|
||||||
|
class RobotInstance(models.Model): |
||||||
|
instanceId = models.CharField(max_length=255) |
||||||
@ -0,0 +1,29 @@ |
|||||||
|
{% load bootstrap3 %} |
||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="en"> |
||||||
|
<head> |
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"> |
||||||
|
{% bootstrap_css %} |
||||||
|
<script src="{% bootstrap_jquery_url %}"></script> |
||||||
|
{% bootstrap_javascript %} |
||||||
|
<title>ATrade dashboard</title> |
||||||
|
</head> |
||||||
|
|
||||||
|
<body> |
||||||
|
<nav class="navbar navbar-default"> |
||||||
|
<div class="navbar-header"> |
||||||
|
<a class="navbar-brand">Dashboard</a> |
||||||
|
</div> |
||||||
|
<ul class="nav navbar-nav"> |
||||||
|
<li><a href="{% url 'overview' %}">Overview</a></li> |
||||||
|
</ul> |
||||||
|
</nav> |
||||||
|
|
||||||
|
{% bootstrap_messages %} |
||||||
|
|
||||||
|
<div id="container"> |
||||||
|
{% block content %}{% endblock %} |
||||||
|
</div> |
||||||
|
</body> |
||||||
|
</html> |
||||||
|
|
||||||
@ -0,0 +1,56 @@ |
|||||||
|
{% extends "dashboard/base.html" %} |
||||||
|
|
||||||
|
{% block content %} |
||||||
|
<div class="panel-group"> |
||||||
|
{% for index, instanceId, state, positions in robot_states %} |
||||||
|
<div class="panel panel-default"> |
||||||
|
<div class="panel-heading" id="heading-{{instanceId}}"> |
||||||
|
<a role="button" data-toggle="collapse" href="#collapse-{{index}}"> |
||||||
|
{{ instanceId }} |
||||||
|
</a> |
||||||
|
</div> |
||||||
|
<div id="collapse-{{index}}" class="panel-collapse collapse"> |
||||||
|
<div class="panel-body"> |
||||||
|
<pre>{{ state }}</pre> |
||||||
|
|
||||||
|
{% for position in positions %} |
||||||
|
<div class="panel panel-default"> |
||||||
|
<div class="panel-body"> |
||||||
|
<p>State: {{ position.posState.tag }} </p> |
||||||
|
<p>Ticker: {{ position.posTicker }} </p> |
||||||
|
<p>Balance: {{ position.posBalance }} </p> |
||||||
|
{% if position.posEntryTime %} |
||||||
|
<p>Entry: {{ position.posEntryTime }} </p> |
||||||
|
{% endif %} |
||||||
|
{% if position.posExitTime %} |
||||||
|
<p>Exit: {{ position.posExitTime }} </p> |
||||||
|
{% endif %} |
||||||
|
{% if position.posStopPrice %} |
||||||
|
<p>Stop at: {{ position.posStopPrice }} </p> |
||||||
|
{% endif %} |
||||||
|
{% if position.posTakeProfitPrice %} |
||||||
|
<p>Take profit at: {{ position.posTakeProfitPrice }} </p> |
||||||
|
{% endif %} |
||||||
|
<p>Account: {{ position.posAccount }} </p> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
{% endfor %} |
||||||
|
|
||||||
|
</div> |
||||||
|
<div class="panel-footer"> |
||||||
|
<a class="btn btn-danger" href="{% url 'delete_instance' instanceId %}">Delete</a> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
{% endfor %} |
||||||
|
</div> |
||||||
|
|
||||||
|
<form class="form-inline" action="{% url 'add_instance' %}" method="POST"> |
||||||
|
{% csrf_token %} |
||||||
|
<div class="form-group"> |
||||||
|
<label for="instance_id">New instance ID:</label> |
||||||
|
<input type="text" class="form-control" id="instance_id" name="instance_id" placeholder="instance ID" /> |
||||||
|
</div> |
||||||
|
<button type="submit" class="btn btn-success">Add</button> |
||||||
|
</form> |
||||||
|
{% endblock %} |
||||||
@ -0,0 +1,3 @@ |
|||||||
|
from django.test import TestCase |
||||||
|
|
||||||
|
# Create your tests here. |
||||||
@ -0,0 +1,11 @@ |
|||||||
|
|
||||||
|
from django.conf.urls import url |
||||||
|
|
||||||
|
from . import views |
||||||
|
|
||||||
|
urlpatterns = [ |
||||||
|
url(r'^$', views.overview, name='overview'), |
||||||
|
url(r'^add_instance$', views.add_instance, name='add_instance'), |
||||||
|
url(r'^delete_instance/(?P<instance_id>[^/]+)$', views.delete_instance, name='delete_instance'), |
||||||
|
|
||||||
|
] |
||||||
@ -0,0 +1,51 @@ |
|||||||
|
|
||||||
|
from django.http import HttpResponse, HttpResponseRedirect |
||||||
|
from django.template import loader |
||||||
|
from django.shortcuts import render, get_object_or_404 |
||||||
|
from django.urls import reverse |
||||||
|
from django.contrib import messages |
||||||
|
|
||||||
|
from .models import RobotInstance |
||||||
|
import redis |
||||||
|
import json |
||||||
|
|
||||||
|
def overview(request): |
||||||
|
r = redis.StrictRedis(unix_socket_path='/var/run/redis/redis') |
||||||
|
robot_instances = RobotInstance.objects.order_by('instanceId') |
||||||
|
robot_states = [] |
||||||
|
index = 0 |
||||||
|
for robot in robot_instances: |
||||||
|
raw_state = r.get(robot.instanceId) |
||||||
|
if raw_state is not None: |
||||||
|
state = json.loads(str(raw_state, 'utf-8')) |
||||||
|
try: |
||||||
|
positions = state['positions'] |
||||||
|
except KeyError: |
||||||
|
positions = dict() |
||||||
|
del state['positions'] |
||||||
|
else: |
||||||
|
state = dict() |
||||||
|
index += 1 |
||||||
|
robot_states.append((index, robot.instanceId, json.dumps(state, sort_keys=True, indent=2, separators=(',', ': ')), positions)) |
||||||
|
|
||||||
|
template = loader.get_template('dashboard/overview.html') |
||||||
|
context = { |
||||||
|
'robot_instances' : robot_instances, |
||||||
|
'robot_states' : robot_states |
||||||
|
} |
||||||
|
return HttpResponse(template.render(context, request)) |
||||||
|
|
||||||
|
def add_instance(request): |
||||||
|
instance_id = request.POST['instance_id'] |
||||||
|
if instance_id == "" or RobotInstance.objects.filter(instanceId=instance_id).count() > 0: |
||||||
|
messages.error(request, 'Invalid instance ID specified') |
||||||
|
else: |
||||||
|
new_instance = RobotInstance(instanceId=instance_id) |
||||||
|
new_instance.save() |
||||||
|
return HttpResponseRedirect(reverse('overview')) |
||||||
|
|
||||||
|
def delete_instance(request, instance_id): |
||||||
|
instance = get_object_or_404(RobotInstance, instanceId=instance_id) |
||||||
|
instance.delete() |
||||||
|
return HttpResponseRedirect(reverse('overview')) |
||||||
|
|
||||||
Loading…
Reference in new issue