| 1 |
import types |
|---|
| 2 |
import time |
|---|
| 3 |
|
|---|
| 4 |
from trac.core import * |
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 |
|
|---|
| 12 |
|
|---|
| 13 |
class InsufficientFunds(Exception): |
|---|
| 14 |
def __str__(self): |
|---|
| 15 |
d = self.args[0] |
|---|
| 16 |
bal = d['balance'] |
|---|
| 17 |
amt = d['amount'] |
|---|
| 18 |
sym = d['symbol'] |
|---|
| 19 |
account = d['account'] |
|---|
| 20 |
out = "Insufficient Funds: " |
|---|
| 21 |
out += "attempted to withdraw, reserve, or spend %f %s, " % (amt, sym) |
|---|
| 22 |
out += "%s balance is only %f" % (account, bal) |
|---|
| 23 |
return out |
|---|
| 24 |
|
|---|
| 25 |
class MissingAccount(Exception): pass |
|---|
| 26 |
|
|---|
| 27 |
class IMarketController(Interface): |
|---|
| 28 |
'''Central controller for tracmarket plugin. UI module(s) talk to |
|---|
| 29 |
the controller. The controller sets up the per-query context (db, |
|---|
| 30 |
message bus, etc.), passes it to the command interpreter one or |
|---|
| 31 |
more times (once for each command), then does the db commit or |
|---|
| 32 |
rollback when UI calls close().''' |
|---|
| 33 |
|
|---|
| 34 |
def open(req, bus=None, db=None): |
|---|
| 35 |
'''Set up the tracmarket subsystem. Returns the system's |
|---|
| 36 |
message bus object, which it creates if none is provided. |
|---|
| 37 |
Opens a db connection if none is provided. The UI controls |
|---|
| 38 |
tracmarket by sending and receiving messages on the bus, and |
|---|
| 39 |
is then responsible for calling .close() at the end of the |
|---|
| 40 |
query.''' |
|---|
| 41 |
|
|---|
| 42 |
def run(bus, cmds): |
|---|
| 43 |
'''Return a generator which sends commands to bus and yields |
|---|
| 44 |
the resulting message stream. Cmds is a list of command |
|---|
| 45 |
strings.''' |
|---|
| 46 |
|
|---|
| 47 |
def close(bus, commit=True): |
|---|
| 48 |
'''Do internal cleanup; call at end of HTTP or other query. |
|---|
| 49 |
If commit=True, then commit db.''' |
|---|
| 50 |
|
|---|
| 51 |
def run_cmd(req, cmd): |
|---|
| 52 |
'''Backward compatibility method. Create bus, execute a |
|---|
| 53 |
single command, close and return internal context when done. |
|---|
| 54 |
Response can be found in ctx.res. This api (and the whole |
|---|
| 55 |
ctx.res tree) is deprecated -- use run() instead.''' |
|---|
| 56 |
|
|---|
| 57 |
|
|---|
| 58 |
|
|---|
| 59 |
class ICommandInterpreter(Interface): |
|---|
| 60 |
"""Extension point interface for components that can handle orders |
|---|
| 61 |
and market data requests for a given contract.""" |
|---|
| 62 |
|
|---|
| 63 |
def match_symbol(symbol, currency): |
|---|
| 64 |
"""Returns True if this component can handle orders and market |
|---|
| 65 |
data requests for symbol, denominated in currency.""" |
|---|
| 66 |
|
|---|
| 67 |
def order(req, size, symbol, currency, **kwargs): |
|---|
| 68 |
"""Create an order to buy or sell 'size' items. Orders with |
|---|
| 69 |
different denominations go into different books; we don't |
|---|
| 70 |
perform automatic currency conversion. Negative size means |
|---|
| 71 |
sell, positive size means buy. Kwargs are specific to the |
|---|
| 72 |
instrument being traded. Returns order object.""" |
|---|
| 73 |
|
|---|
| 74 |
def cancel(req, order_id): |
|---|
| 75 |
"""Cancel an order. Returns order object -- check contents |
|---|
| 76 |
for status.""" |
|---|
| 77 |
|
|---|
| 78 |
def open_orders(req, user): |
|---|
| 79 |
"""Return a list of open order objects for user.""" |
|---|
| 80 |
|
|---|
| 81 |
|
|---|
| 82 |
def quote(symbol, currency, last_count=1): |
|---|
| 83 |
"""Return a consolidated quote containing order book and |
|---|
| 84 |
'last_count' number of trades. See model.py for definition of |
|---|
| 85 |
Quote, Book, Order, and Trade objects.""" |
|---|
| 86 |
|
|---|
| 87 |
|
|---|
| 88 |
|
|---|
| 89 |
class ILedger(Interface): |
|---|
| 90 |
"""Extension point interface for components that can store |
|---|
| 91 |
and report double-entry transactions for currency and inventory |
|---|
| 92 |
items. |
|---|
| 93 |
""" |
|---|
| 94 |
|
|---|
| 95 |
def post(req, legs, memo=''): |
|---|
| 96 |
"""Record a transaction; 'legs' is a list of transaction legs |
|---|
| 97 |
that have been created using mkleg(). Memo is a string. Legs |
|---|
| 98 |
can be mixed-currency. Ensures debits and credits are |
|---|
| 99 |
balanced within each currency. Adds remote_user and |
|---|
| 100 |
timestamp. Returns integer transaction id.""" |
|---|
| 101 |
|
|---|
| 102 |
|
|---|
| 103 |
def mkleg(entity, account, symbol, amount, serial=None): |
|---|
| 104 |
"""Convenience method to help create a proper transaction leg. |
|---|
| 105 |
Does no storage. Returns an object suitable for sending to |
|---|
| 106 |
post(). Entity is an entity string. Account is an account name |
|---|
| 107 |
string. Symbol is a string, and can be any symbol previously |
|---|
| 108 |
defined by mksymbol(). Amount is a signed float, and will be |
|---|
| 109 |
converted to debit or credit depending on normal balance of |
|---|
| 110 |
account. Serial is an optional string, and is used to |
|---|
| 111 |
designate a unique instance of symbol to be transferred, e.g. |
|---|
| 112 |
equipment, stock certificate, or banknote serial number. |
|---|
| 113 |
Returns None if insufficient funds available in account.""" |
|---|
| 114 |
|
|---|
| 115 |
|
|---|
| 116 |
def mkentity(entity, description): |
|---|
| 117 |
"""Create a legal entity to group accounts under -- person, |
|---|
| 118 |
corporation, etc. Entity is a unique string. Description is |
|---|
| 119 |
a string.""" |
|---|
| 120 |
|
|---|
| 121 |
|
|---|
| 122 |
def chentity(entity, description=None): |
|---|
| 123 |
"""Change entity attributes.""" |
|---|
| 124 |
|
|---|
| 125 |
def mkaccount(entity, account, description, normal_balance): |
|---|
| 126 |
"""Create a currency or inventory account for entity. Account |
|---|
| 127 |
is an account name string. Description is a string. |
|---|
| 128 |
Normal_balance is a string: 'debit' or 'credit'.""" |
|---|
| 129 |
|
|---|
| 130 |
|
|---|
| 131 |
def chaccount(entity, account, description=None): |
|---|
| 132 |
"""Change account attributes.""" |
|---|
| 133 |
|
|---|
| 134 |
def mksymbol(symbol, description, divisible): |
|---|
| 135 |
"""Create a currency or inventory item symbol for later use in |
|---|
| 136 |
transaction legs. Symbol is a string (no spaces), and might |
|---|
| 137 |
be a currency symbol, part number, or similar. Description is |
|---|
| 138 |
a string. Divisible is a boolean; if false, it means that |
|---|
| 139 |
amounts must be equal to a round integer; for example, a |
|---|
| 140 |
dollar is divisible, but an inventory item might not be.""" |
|---|
| 141 |
|
|---|
| 142 |
|
|---|
| 143 |
def history(entity=None, account=None, symbol=None, |
|---|
| 144 |
start_date=None, end_date=None, count=None): |
|---|
| 145 |
"""Return a list of transaction objects, sorted by |
|---|
| 146 |
date.""" |
|---|
| 147 |
|
|---|
| 148 |
|
|---|
| 149 |
|
|---|
| 150 |
def balance(entity, account, symbol, serial=None): |
|---|
| 151 |
"""Return quantity of symbol in account.""" |
|---|
| 152 |
|
|---|
| 153 |
|
|---|