-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathma_arb.py
153 lines (133 loc) · 3.92 KB
/
ma_arb.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# Graph object class
import math
class Graph:
"""
A class to represent a graph.
Attributes
-------------
V : int
number of vertices in the graph.
vertices : [str]
list of vertices in the graph.
edges : {str: double}
dictionary of edges. the key is the start and destination vertex in the format {start}-{destination}.
the value of each key is the weight of that edge.
path : [str]
the path found by the algorithm.
----------
"""
def __init__(self):
self.V = 0 # Number of vertices (Obsolete)
self.vertices = [] # Array of vertices
self.edges = {} # Array of edges
self.path = []
# Add edges
def add_edge(self, s, d, w):
"""
Parameters
----------
s: str
starting vertex
d: str
destination vertex
w: double
weight of edge - exchange rate from asset s to asset d
----------
"""
if s not in self.vertices:
self.vertices.append(s)
self.V += 1
if d not in self.vertices:
self.vertices.append(d)
self.V += 1
self.edges["{}-{}".format(s, d)] = float(w)
def update_edge(self, s, d, w):
"""
Parameters
----------
s : str
starting vertex
d: str
destination vertex
w: double
weight of edge - exchange rate from asset s to asset d
----------
"""
self.edges["{}-{}".format(s, d)] = w
def print_solution(self):
"""
Prints the solution to the terminal
"""
path_string = "Path: "
for v in self.path:
path_string += v + " "
print(path_string)
print("Profit: {:.2f}%".format(self.calculate_profit()))
def calculate_profit(self):
"""
This function calculates the profit of the self.path arbitrage path.
"""
profit = 1.0
i = 0
while i < len(self.path) - 1:
edge = "{}-{}".format(self.path[i], self.path[i + 1])
rate = self.edges[edge]
profit = profit * rate
i += 1
profit = (profit - 1) * 100
return profit
def bellman_ford(self, src):
"""
Parameters
----------
src: str
source vertex
----------
Modified Bellman-Ford algorithm.
"""
self.path = []
# Step 1: fill the distance array and predecessor array
dist = {}
prev = {}
for v in self.vertices:
dist[v] = -float("Inf")
prev[v] = []
# Mark the source vertex
dist[src] = 0
# Step 2: "relax" edges |V| - 1 times
for _ in range(self.V - 1):
for edge in self.edges:
s, d = edge.split("-") # assign source and destination vertex
w = self.edges[edge] # assign weight
if dist[s] != -float("Inf") and dist[s] + math.log(w) > dist[d]:
if s not in prev[d]:
dist[d] = dist[s] + math.log(w)
prev[d] = prev[s] + [s]
# Set class attribute path
self.path = prev[src] + [src]
self.print_solution()
# self.build_path(prev, dist, src)
return
g = Graph()
g.add_edge("A", "B", 1.0)
g.add_edge("A", "C", 1.0)
g.add_edge("B", "C", 1.0)
g.add_edge("B", "A", 1.0)
g.add_edge("C", "A", 1.0)
g.add_edge("C", "B", 1.0)
g.add_edge("A", "Z", 0.5)
g.add_edge("Z", "A", 2)
g.add_edge("B", "Z", 0.5)
g.add_edge("Z", "B", 2.0)
g.add_edge("C", "Z", 1 / 2.01)
g.add_edge("Z", "C", 2.01)
g.add_edge("B", "S", 2.0)
g.add_edge("S", "T", 1.0)
g.add_edge("T", "B", 0.51)
g.add_edge("S", "B", 0.5)
g.add_edge("T", "S", 1.0)
g.add_edge("B", "T", 1 / 0.51)
g.add_edge("Q", "C", 1.0)
g.add_edge("C", "Q", 1.0)
ins = input("Enter starting vertex: ")
g.bellman_ford(ins)