Completed
Push — master ( fe17c6...2f219c )
by Rafael S.
01:35
created

Context.fetch_occurrences()   A

Complexity

Conditions 2

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
1
"""trade
2
3
trade: Financial Application Framework
4
http://trade.readthedocs.org/
5
https://github.com/rochars/trade
6
License: MIT
7
8
Copyright (c) 2015-2018 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
from __future__ import division
31
32
import copy
33
34
from . daytrade import (
35
    Daytrade,
36
    merge_operations,
37
    daytrade_condition
38
)
39
40
41
class Context(object):
0 ignored issues
show
Unused Code introduced by
The variable __class__ seems to be unused.
Loading history...
42
    """A container for operations."""
43
44
    def __init__(self, operations, tasks):
45
        self.operations = operations
46
        self.tasks = tasks
47
        self.data = {}
48
49
    def fetch_occurrences(self):
50
        """Run the the methods defined in self.tasks.
51
52
        This method executes all the methods defined in self.tasks
53
        in the order that they are listed, applying the context rules
54
        to all operations in the context.
55
        """
56
        raw_operations = copy.deepcopy(self.operations)
57
        for task in self.tasks:
58
            task(self)
59
        self.operations = raw_operations
60
61
62
# Default context rules:
63
64
def find_volume(container):
65
    """Find the volume of the operations in the container."""
66
    container.data['volume'] = sum(
67
        operation.volume for operation in container.operations
68
    )
69
70
def group_positions(container):
71
    """Group the container operations with the same asset."""
72
    if 'occurrences' not in container.data:
73
        container.data['occurrences'] = {}
74
    for operation in container.operations:
75
        group_position(container, operation)
76
77
def group_position(container, operation):
78
    """Group one operation in the container positions."""
79
    if operation.quantity != 0 and operation.update_container:
80
        add_to_position_group(container, operation)
81
82
def add_to_position_group(container, operation):
83
    """Adds an operation to the common operations list."""
84
    if 'operations' not in container.data['occurrences']:
85
        container.data['occurrences']['operations'] = {}
86
    if operation.subject.symbol in container.data['occurrences']['operations']:
87
        merge_operations(
88
            container.data['occurrences']\
89
                ['operations'][operation.subject.symbol],
90
            operation
91
        )
92
    else:
93
        container.data['occurrences']\
94
            ['operations'][operation.subject.symbol] = operation
95
96
def fetch_daytrades(container):
97
    """An OperationContainer task.
98
99
    Fetches the daytrades from the OperationContainer operations.
100
101
    The daytrades are placed on the container positions under the
102
    'daytrades' key, inexed by the Daytrade asset's symbol.
103
    """
104
    for index, operation in enumerate(container.operations):
105
        find_daytrade_pair(index, operation, container)
106
107
def find_daytrade_pair(operation_a_index, operation_a, container):
108
    """Search for possible daytrade pairs for a operation.
109
110
    If a daytrade is found, a Daytrade object is created and appended
111
    to the container positions.
112
    """
113
    for operation_b in [
114
            x for x in container.operations[operation_a_index:] if\
115
                daytrade_condition(x, operation_a)
116
        ]:
117
        Daytrade(operation_a, operation_b).append_to_positions(container)
118
119
def prorate_commissions(container):
120
    """Prorates the container's commissions by its operations.
121
122
    This method sum the discounts in the commissions dict of the
123
    container. The total discount value is then prorated by the
124
    position operations based on their volume.
125
    """
126
    if 'occurrences' in container.data:
127
        for position_value in container.data['occurrences'].values():
128
            for position in position_value.values():
129
                prorate(container, position)
130
131
def prorate(container, position):
132
    """Prorate the commissions for one position."""
133
    if position.update_position:
134
        prorate_commissions_by_position(container, position)
135
    else:
136
        for operation in position.operations:
137
            prorate_commissions_by_position(container, operation)
138
139
def prorate_commissions_by_position(container, operation):
140
    """Prorates the commissions of the container for one position.
141
142
    The ratio is based on the container volume and the volume of
143
    the position operation.
144
    """
145
    if can_prorate_commission(container, operation):
146
        percent = operation.volume / container.data['volume'] * 100
147
        for key, value in container.commissions.items():
148
            operation.commissions[key] = value * percent / 100
149
150
def can_prorate_commission(container, operation):
151
    """Check if the commissions can be divided by the positions or not."""
152
    if 'volume' in container.data:
153
        if operation.volume != 0 and container.data['volume'] != 0:
154
            return True
155