Passed
Push — master ( 29f120...0f38db )
by Rafael S.
01:41
created

trade/trade_json.py (2 issues)

1
"""trade JSON interface.
2
3
trade: Financial Application Framework
4
https://github.com/rochars/trade
5
http://trade.readthedocs.org/
6
License: MIT
7
8
Copyright (c) 2015-2017 Rafael da Silva Rocha
9
10
Permission is hereby granted, free of charge, to any person obtaining a copy
11
of this software and associated documentation files (the "Software"), to deal
12
in the Software without restriction, including without limitation the rights
13
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
copies of the Software, and to permit persons to whom the Software is
15
furnished to do so, subject to the following conditions:
16
17
The above copyright notice and this permission notice shall be included in
18
all copies or substantial portions of the Software.
19
20
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26
THE SOFTWARE.
27
"""
28
29
from __future__ import absolute_import
30
31
import json
32
33
from . holder import Holder
34
from . context import Context
35
36
37
class TradeJSON(object):
0 ignored issues
show
Too many instance attributes (8/7)
Loading history...
38
    """trade JSON interface."""
39
40
    def __init__(self, container_tasks, types):
41
        self.subjects = {}
42
        self.occurrences = []
43
        self.containers = {}
44
        self.container_tasks = container_tasks
45
        self.types = types
46
        self.portfolio = None
47
        self.totals = {
48
            'total_operations': 0,
49
            'sale_operations': 0,
50
            'purchase_operations': 0,
51
            'sale_volume': 0,
52
            'purchase_volume': 0,
53
            'total_daytrades': 0
54
        }
55
56
    def create_subjects(self, data):
57
        """creates a subject object for all subjects in the json."""
58
        self.create_subject(data)
59
        self.create_subject_underlying()
60
61
    def create_subject(self, data):
62
        """Create one subject from a subject in the JSON."""
63
        for subject, details in data['subjects'].items():
64
            self.subjects[subject] = {
65
                'object': self.types[details['type']](
66
                    name=details['name'],
67
                    symbol=subject,
68
                    expiration_date=details.get('expiration_date', None),
69
                    underlying_assets=details.get('underlying_assets', {})
70
                ),
71
                'sales': 0,
72
                'purchases': 0,
73
                'daytrades': 0,
74
                'operations': 0
75
            }
76
77
    def create_subject_underlying(self):
78
        """Create the underlying objects of one subject."""
79
        for obj in self.subjects.values():
80
            if obj['object'].underlying_assets:
81
                original_underlying = obj['object'].underlying_assets
82
                underlying_assets = {}
83
                for underlying, ratio in original_underlying.items():
84
                    underlying_assets\
85
                        [self.subjects[underlying]['object']] = ratio
86
                obj['object'].underlying_assets = underlying_assets
87
88
    def create_occurrences(self, data):
89
        """Creates all the occurrences described in the json."""
90
        self.occurrences = []
91
        for occurrence in data['occurrences']:
92
            self.occurrences.append(
93
                self.types[occurrence['type']](
94
                    quantity=occurrence['quantity'],
95
                    price=occurrence['price'],
96
                    date=occurrence['date'],
97
                    subject=self.subjects[occurrence['subject']]['object']
98
                )
99
            )
100
            self.totals['total_operations'] += 1
101
            self.subjects[occurrence['subject']]['operations'] += 1
102
            volume = abs(occurrence['quantity'] * occurrence['price'])
103
            if occurrence['quantity'] > 0:
104
                self.totals['purchase_operations'] += 1
105
                self.totals['purchase_volume'] += volume
106
                self.subjects[occurrence['subject']]['purchases'] += 1
107
            else:
108
                self.totals['sale_operations'] += 1
109
                self.totals['sale_volume'] += volume
110
                self.subjects[occurrence['subject']]['sales'] += 1
111
112
    def create_containers(self):
113
        """Creates a container for each operation date.
114
115
        The containers are then filled with the respective operations.
116
        """
117
        for occurrence in self.occurrences:
118
            if occurrence.date not in self.containers:
119
                self.containers[occurrence.date] = Context(
120
                    operations=[],
121
                    tasks=self.container_tasks
122
                )
123
            self.containers[occurrence.date].operations.append(occurrence)
124
125
    def create_portfolio(self, data):
126
        """Create a portfolio to store the positions."""
127
        initial_state = {}
128
        for asset_name, asset_state in data['initial state'].items():
129
            initial_state[self.subjects[asset_name]['object']] = asset_state
130
        self.holder = Holder(state=initial_state)
0 ignored issues
show
The attribute holder was defined outside __init__.

It is generally a good practice to initialize all attributes to default values in the __init__ method:

class Foo:
    def __init__(self, x=None):
        self.x = x
Loading history...
131
132
    def accumulate_positions(self):
133
        """Accumulate each container position on the portoflio."""
134
        for key in sorted(self.containers.keys()):
135
            self.containers[key].fetch_positions()
136
            if 'positions' in self.containers[key].context:
137
                self.accumulate_position(key)
138
139
    def accumulate_position(self, key):
140
        """Accumulate one position in the portfolio."""
141
        for position_type, position_asset in \
142
            self.containers[key].context['positions'].items():
143
            for asset_symbol, position in position_asset.items():
144
                self.holder.accumulate(position)
145
                if position_type == 'daytrades':
146
                    self.totals['total_daytrades'] += 1
147
                    self.subjects[asset_symbol]['daytrades'] += 1
148
149
    def get_base_log(self):
150
        """Get the structure of the return json."""
151
        return {
152
            'totals': {
153
                "sales": {
154
                    "volume": self.totals['sale_volume'],
155
                    "operations": self.totals['sale_operations']
156
                },
157
                "purchases": {
158
                    "volume": self.totals['purchase_volume'],
159
                    "operations": self.totals['purchase_operations']
160
                },
161
                "operations": self.totals['total_operations'],
162
                "daytrades": self.totals['total_daytrades'],
163
                'results' : {}
164
            },
165
            'assets': {}
166
        }
167
168
    def get_states(self):
169
        """Fill the return json with the log of each accumulator."""
170
        logs = self.get_base_log()
171
        for accumulator in self.holder.subjects.values():
172
            if accumulator.subject.symbol not in logs['assets']:
173
                self.get_state(accumulator, logs)
174
        return logs
175
176
    def get_state(self, accumulator, logs):
177
        """Get the state of one subject."""
178
        logs['assets'][accumulator.subject.symbol] = {
179
            'totals': {
180
                "sales": self.subjects\
181
                    [accumulator.subject.symbol]['sales'],
182
                "purchases": self.subjects\
183
                    [accumulator.subject.symbol]['purchases'],
184
                "operations": self.subjects\
185
                    [accumulator.subject.symbol]['operations'],
186
                "daytrades": self.subjects\
187
                    [accumulator.subject.symbol]['daytrades'],
188
                "results": accumulator.state['results']
189
            },
190
            'states': {}
191
        }
192
        logs['assets'][accumulator.subject.symbol]['states'] = \
193
            accumulator.log
194
        for key in accumulator.state['results'].keys():
195
            if key not in logs['totals']['results']:
196
                logs['totals']['results'][key] = 0
197
            logs['totals']['results'][key] += accumulator.state['results']\
198
                [key]
199
200
    def get_trade_results(self, data):
201
        """json in, json out"""
202
        data = json.loads(data)
203
        self.create_subjects(data)
204
        self.create_occurrences(data)
205
        self.create_portfolio(data)
206
        self.create_containers()
207
        self.accumulate_positions()
208
        json_output = json.dumps(self.get_states())
209
        return json_output
210