aboutsummaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/Dawn/models.py33
-rw-r--r--python/Dawn/templates/base.html8
-rw-r--r--python/Dawn/templates/wire_blotter.html40
-rw-r--r--python/Dawn/templates/wire_entry.html51
-rw-r--r--python/Dawn/views.py65
5 files changed, 188 insertions, 9 deletions
diff --git a/python/Dawn/models.py b/python/Dawn/models.py
index 4bda22d7..fd33926b 100644
--- a/python/Dawn/models.py
+++ b/python/Dawn/models.py
@@ -29,6 +29,14 @@ class Counterparties(db.Model):
notes = db.Column(db.String)
instructions = db.Column(db.String, info={'form_field_class': FileField})
+class Accounts(db.Model):
+ __tablename__ = 'accounts'
+ code = db.Column(db.String(5), primary_key=True)
+ name = db.Column(db.String)
+ custodian = db.Column(db.String)
+ cash_account = db.Column(db.String)
+ counterpaty = db.Column(db.String, db.ForeignKey('counterparties.code'))
+
BOND_STRAT = ENUM('M_STR_MAV', 'M_STR_MEZZ', 'CSO_TRANCH',
'M_CLO_BB20', 'M_CLO_AAA', 'M_CLO_BBB', 'M_MTG_IO', 'M_MTG_THRU',
'M_MTG_GOOD', 'M_MTG_B4PR', 'M_MTG_RW', 'M_MTG_FP', 'M_MTG_LMG',
@@ -45,6 +53,10 @@ SWAPTION_STRAT = ENUM('IGPAYER', 'IGREC', 'HYPAYER', 'HYREC',
FUTURE_STRAT = ENUM('M_STR_MAV', 'M_MTG_IO', 'M_STR_MEZZ', 'M_MTG_RW', 'SER_ITRXCURVE',
name='future_strat')
+CASH_STRAT = ENUM('M_CSH_CASH', 'MBSCDSCSH', 'SER_IGCVECSH', 'SER_ITRXCVCSH', 'CSOCDSCSH',
+ 'IGCDSCSH', 'HYCDSCSH', 'CLOCDSCSH', 'IGTCDSCSH', 'MACCDSCSH',
+ name='cash_strat')
+
SWAPTION_TYPE = ENUM('PAYER', 'RECEIVER',
name='swaption_type')
@@ -83,10 +95,10 @@ class BondDeal(db.Model):
cashaccount = db.Column(db.String(10), default='V0NSCLMAMB', nullable=False)
cp_code = db.Column(db.String(12), db.ForeignKey('counterparties.code'),
info={'choices': [(None, '')],
- 'label': 'counterparty'}, nullable = False)
+ 'label': 'counterparty'}, nullable=False)
trade_date = db.Column(db.Date, nullable = False)
settle_date = db.Column(db.Date, nullable = False)
- cusip = db.Column(db.String(9), info={'validators': Length(9,9),
+ cusip = db.Column(db.String(9), info={'validators': Length(9, 9),
'filters': [lambda x: x or None,],
'trim': True})
isin = db.Column(db.String(12), info={'validators': Length(12, 12),
@@ -197,7 +209,7 @@ class SwaptionDeal(db.Model):
trade_date = db.Column(db.Date, nullable=False)
settle_date = db.Column(db.Date, nullable=False)
buysell = db.Column(db.Boolean, nullable=False, info={'choices':[(0, 'sell'), (1, 'buy')],
- 'coerce': lambda x: bool(int(x)) \
+ 'coerce': lambda x: bool(int(x)) \
if x is not None else x})
notional = db.Column(db.Float, nullable=False)
swaption_type = db.Column(SWAPTION_TYPE, nullable=False)
@@ -241,6 +253,21 @@ class FutureDeal(db.Model):
exchange = db.Column(db.String(3), default='CME', nullable=False)
counterparty = db.relationship(Counterparties)
+class CashFlowDeal(db.Model):
+ __tablename__ = 'wires'
+ id = db.Column('id', db.Integer, primary_key=True)
+ dealid = db.Column(db.String(28))
+ lastupdate = db.Column(db.DateTime, server_default=db.func.now(), onupdate=db.func.now())
+ action = db.Column(ACTION)
+ folder = db.Column(CASH_STRAT, nullable=False)
+ code = db.Column(db.String(5), db.ForeignKey('accounts.code'),
+ info={'choices': [('IB', 'pomme')],
+ 'label': 'account'}, nullable=False)
+ amount = db.Column(db.Float, nullable=False)
+ trade_date = db.Column(db.Date, nullable=False)
+ settle_date = db.Column(db.Date, nullable=False)
+ account = db.relationship(Accounts)
+
BaseModelForm = model_form_factory(FlaskForm)
class ModelForm(BaseModelForm):
@classmethod
diff --git a/python/Dawn/templates/base.html b/python/Dawn/templates/base.html
index a17f98d3..ab2c005d 100644
--- a/python/Dawn/templates/base.html
+++ b/python/Dawn/templates/base.html
@@ -21,13 +21,14 @@
data-toggle="dropdown"
role="button"
aria-haspopup="true"
- aria-expanded="false">Blotter <span class="caret"></span>
+ aria-expanded="false">Blotter<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a href="{{url_for('list_trades', kind='bond')}}">Bonds</a></li>
<li><a href="{{url_for('list_trades', kind='cds')}}">CDS</a></li>
<li><a href="{{url_for('list_trades', kind='swaption')}}">Swaptions</a></li>
<li><a href="{{url_for('list_trades', kind='future')}}">Futures</a></li>
+ <li><a href="{{url_for('list_trades', kind='wire')}}">Wires</a></li>
</ul>
</li>
<li class="dropdown">
@@ -35,13 +36,14 @@
data-toggle="dropdown"
role="button"
aria-haspopup="true"
- aria-expanded="false">Book <span class="caret"></span>
+ aria-expanded="false">Book<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a href="{{url_for('trade_manage', kind='bond')}}">Bonds</a></li>
<li><a href="{{url_for('trade_manage', kind='cds')}}">CDS</a></li>
<li><a href="{{url_for('trade_manage', kind='swaption')}}">Swaptions</a></li>
<li><a href="{{url_for('trade_manage', kind='future')}}">Futures</a></li>
+ <li><a href="{{url_for('wire_manage')}}">Wires</a></li>
</ul>
</li>
<li class="dropdown">
@@ -49,7 +51,7 @@
data-toggle="dropdown"
role="button"
aria-haspopup="true"
- aria-expanded="false">Counterparties <span class="caret"></span>
+ aria-expanded="false">Counterparties<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a href="../counterparties">List</a></li>
diff --git a/python/Dawn/templates/wire_blotter.html b/python/Dawn/templates/wire_blotter.html
new file mode 100644
index 00000000..8397e5df
--- /dev/null
+++ b/python/Dawn/templates/wire_blotter.html
@@ -0,0 +1,40 @@
+{% extends "base.html" %}
+{% block content %}
+<table class="table table-striped">
+ <thead>
+ <tr>
+ <td>Deal ID</td>
+ <td>Trade Date</td>
+ <td>Settle Date</td>
+ <td>Buy/Sell</td>
+ <td>Quantity</td>
+ <td>Type</td>
+ <td>Maturity</td>
+ <td>Price</td>
+ <td>Commission</td>
+ <td>Description</td>
+ <td>Ticker</td>
+ <td>Counterparty</td>
+ <td>Strategy</td>
+ </tr>
+ </thead>
+ {% for trade in trades %}
+ <tr>
+ <td><a href="{{url_for('wire_manage', wire_id=wire.id)}}">{{wire.dealid}}</a></td>
+ <td>{{trade.trade_date}}</td>
+ <td>{{trade.settle_date}}</td>
+ <td>{% if trade.buysell %}Buy{% else %}Sell{% endif %}</td>
+ <td>{{trade.quantity}}</td>
+ <td>{{trade.swap_type}}</td>
+ <td>{{trade.maturity}}</td>
+ <td>{{trade.price}}</td>
+ <td>{{trade.commission}}</td>
+ <td>{{trade.security_desc}}</td>
+ <td>{{trade.bbg_ticker}}</td>
+ <td><a href="{{url_for('edit_counterparty',
+ cpcode=trade.counterparty.code)}}">{{trade.counterparty.name}}</a></td>
+ <td>{{trade.folder}}</td>
+ </tr>
+ {% endfor %}
+</table>
+{% endblock %}
diff --git a/python/Dawn/templates/wire_entry.html b/python/Dawn/templates/wire_entry.html
new file mode 100644
index 00000000..a5da6b2b
--- /dev/null
+++ b/python/Dawn/templates/wire_entry.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
+ </head>
+ <body style="max-width:1024px; margin:0 auto">
+ <datalist id="index_list"></datalist>
+ <form method="POST" class="form-horizontal"
+ action="{{action_url}}" enctype="multipart/form-data">
+ {% for field in form if field.type != 'BooleanField' %}
+ <div class="form-group {% if field.id in form.errors %}has-error{% endif %}">
+ {% if field.type != 'CSRFTokenField' %}
+ <label class="control-label col-md-2" for="{{ field.id }}">
+ {{ field.label.text }}
+ </label>
+ {% endif %}
+ <div class="col-md-3">
+ {{ field(class_="form-control") }}
+ </div>
+ {% if field.id in form.errors %}
+ <div class="col-md-3">
+ {{form.errors[field.id][0]}}
+ </div>{% endif %}
+ </div>
+ {% endfor %}
+ <div class="form-group">
+ <div class="col-md-offset-2 col-md-3">
+ <div class="checkbox">
+ <label>
+ <input id="upload_globeop" name="upload_globeop" type="checkbox" value="y">Upload to globeop?
+ </label>
+ </div>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="col-md-offset-2 col-md-3">
+ <button type="submit" class="btn btn-default">Submit</button>
+ </div>
+ </div>
+ </form>
+ {% if 'cds' or 'swaption' in action_url %}
+ <script type="text/javascript" src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
+ <script type="text/javascript"
+ src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"
+ integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS"
+ crossorigin="anonymous"></script>
+ <script type="text/javascript" src="{{ url_for('static', filename='dawn.js') }}"></script>
+ {% endif %}
+ </body>
+</html>
diff --git a/python/Dawn/views.py b/python/Dawn/views.py
index 2d1d55d8..761fdd5b 100644
--- a/python/Dawn/views.py
+++ b/python/Dawn/views.py
@@ -1,6 +1,9 @@
from flask import (request, render_template, redirect,
url_for, send_from_directory, send_file, g, jsonify)
-from .models import ModelForm, BondDeal, CDSDeal, SwaptionDeal, FutureDeal, Counterparties
+from .models import (ModelForm,
+ BondDeal, CDSDeal, SwaptionDeal, FutureDeal, CashFlowDeal,
+ Counterparties, Accounts)
+
from sqlalchemy.exc import IntegrityError
from wtforms.fields import BooleanField
import pandas as pd
@@ -32,6 +35,9 @@ def cp_choices(kind='bond'):
filter(Counterparties.name.ilike('%CDS%')).
with_entities(Counterparties.code, Counterparties.name))
+def account_codes():
+ return Accounts.query.order_by('code').with_entities(Accounts.code, Accounts.code)
+
def get_queue():
q = getattr(g, 'queue', None)
if q is None:
@@ -90,6 +96,13 @@ class FutureForm(ModelForm):
include_foreign_keys = True
exclude = ['dealid', 'lastupdate']
+class WireForm(ModelForm):
+ upload_globeop = BooleanField(label="Upload to globeop?")
+ class Meta:
+ model = CashFlowDeal
+ include_foreign_keys = True
+ exclude = ['dealid', 'lastupdate']
+
def get_deal(kind):
if kind == 'cds':
return CDSDeal
@@ -139,10 +152,21 @@ def get_form(trade, kind):
continue
return form
+def get_wire_form(wire):
+ if wire.id:
+ return WireForm(obj=trade)
+ else:
+ today = pd.datetime.today()
+ form = WireForm(trade_date=today.date())
+ return form
+
def get_trade(tradeid, kind):
Deal = get_deal(kind)
return Deal.query.get(tradeid) if tradeid else Deal()
+def get_wire(wiredid):
+ CashFlowDeal.query.get(wireid)
+
def save_ticket(trade, old_ticket_name):
if trade.ticket:
if old_ticket_name:
@@ -156,6 +180,39 @@ def save_ticket(trade, old_ticket_name):
else:
trade.ticket = old_ticket_name
+@app.route('/wires/<int:wire_id>', methods = ['GET', 'POST'])
+@app.route('/wires/', defaults = {'wire_id': None}, methods = ['GET', 'POST'])
+def wire_manage(wire_id):
+ if wire_id is None:
+ wire = CashFlowDeal()
+ else:
+ wire = CashFlowDeal().query.get(wire_id)
+ form = WireForm()
+ form.code.choices = form.code.choices + list(account_codes())
+ if form.validate_on_submit():
+ form.populate_obj(wire)
+ session = form.get_session()
+ if not wire_id:
+ session.add(wire)
+ try:
+ session.commit()
+ except IntegrityError as e:
+ app.logger.error(e)
+ session.rollback()
+ return render_template('wire_entry.html', form=form,
+ action_url=
+ url_for('wire_manage', wire_id=wire_id))
+ else:
+ if form.upload_globeop.data:
+ q = get_queue()
+ q.rpush('wires', simple_serialize(wire))
+ return redirect(url_for('list_trades'))
+ else:
+ form = get_wire_form(wire)
+ form.code.choices = form.code.choices + list(account_codes())
+ return render_template('wire_entry.html', form=form,
+ action_url = url_for('wire_manage', wire_id=wire_id))
+
@app.route('/trades/<kind>/<int:tradeid>', methods = ['GET', 'POST'])
@app.route('/trades/<kind>/', defaults = {'tradeid': None}, methods = ['GET', 'POST'])
@app.route('/trades/', defaults = {'tradeid': None, 'kind': 'bond'}, methods = ['GET', 'POST'])
@@ -196,11 +253,13 @@ def trade_manage(tradeid, kind):
@app.route('/blotter/<kind>')
@app.route('/blotter/', defaults={'kind': 'bond'})
def list_trades(kind):
- Deal = get_deal(kind)
+ if kind == 'wire':
+ Deal = CashFlowDeal()
+ else:
+ Deal = get_deal(kind)
trade_list = Deal.query.order_by(Deal.trade_date.desc(), Deal.id.desc())
return render_template('{}_blotter.html'.format(kind), trades=trade_list.all())
-
@app.route('/tickets/<int:tradeid>')
def download_ticket(tradeid):
trade = BondDeal.query.get(tradeid)