-
-
Notifications
You must be signed in to change notification settings - Fork 140
/
StrategyMonitor.java
172 lines (157 loc) · 7.47 KB
/
StrategyMonitor.java
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
package com.univocity.trader.strategy;
import com.univocity.trader.account.*;
import com.univocity.trader.candles.*;
import com.univocity.trader.indicators.*;
/**
* Class responsible for monitoring trades made by a {@link Trader}, after a {@link Strategy} returns a {@link Signal}.
* It can contain {@link Indicator}s to help deciding what to do on every tick received from the
* {@link com.univocity.trader.Exchange}. Once a {@code BUY} is received, and no position is open,
* {@link #discardBuy(Strategy)} will be invoked to confirm if it is a good time to buy. If it is, a position is open
* and {@link #bought(Trade, Order)} will be called. After that, {@link #handleStop(Trade)} will be
* invoked after every tick received from the exchange, to allow closing the {@link Trade}.
*
* If {@link #handleStop(Trade)} returns a not {@code null} value or a {@code SELL} signal is received'
* from the {@link Strategy}, {@link #allowExit(Trade)} will be invoked to confirm whether to exit the trade. If the
* trade is closed, {@link #sold(Trade, Order)} will be invoked. During the lifetime of the trade, a few other methods
* might be invoked:
*
* - {@link #highestProfit(Trade, double)} when a winning trade reaches a new high positive rate of return.
* - {@link #worstLoss(Trade, double)} when a losing trade is reaches a new low negative rate of return.
* - {@link #allowTradeSwitch(Trade, String, Candle, String)} when there are no funds available to trade anymore and
* a {@link Strategy} finds a buying opportunity, this method will be called to ask if the current trade can be exited
* to release funds and open another trade in another instrument. Specific details about the trade can be obtained from
* the {@link Trader} instance.
*
* @see Trader
* @see IndicatorGroup
* @see Strategy
*/
public abstract class StrategyMonitor extends IndicatorGroup {
/**
* Contextual information about the current trading state of a symbol.
*/
protected Context context;
/**
* The object responsible for creating and managing trades.
*/
protected Trader trader;
/**
* Tests the current trade status to determine whether or not it should be exited. Will exit a trade regardless of
* any {@link Signal} emitted by a {@link Strategy}
*
* @param trade a group of multiple orders that control the state of a position held by the {@link #trader}
*
* @return {@code null} if the trade is to remain open or a {@code String} with a message indicating the reason
* for exiting the trade. This message will then be returned by
* {@link Trade#exitReason()} and can be included in logs or e-mails
* (as implemented in {@link com.univocity.trader.notification.OrderExecutionToEmail}).
*/
public String handleStop(Trade trade) {
return null;
}
/**
* Checks if the {@code BUY} signal emitted by a given {@link Strategy} must be discarded, preventing the
* {@link Trader} to buy.
*
* @param strategy the strategy the emitted a {@code BUY} signal
*
* @return {@code false} if the {@link #trader} is allowed to buy into the instrument it is responsible for; {@code true} if the {@code BUY} signal should be ignored.
*/
public boolean discardBuy(Strategy strategy) {
return false;
}
/**
* Checks if the {@code SELL} signal emitted by a given {@link Strategy} must be discarded, preventing the
* {@link Trader} to sell short.
*
* @param strategy the strategy the emitted a {@code SELL} signal
*
* @return {@code false} if the {@link #trader} is allowed to open a short trade using the instrument it is responsible for; {@code true} if the {@code SELL} signal should be ignored.
*/
public boolean discardShortSell(Strategy strategy) {
return false;
}
/**
* Indicates whether this monitor allows signals from multiple strategies, i.e. if more than one {@link Strategy}
* is being used, one can emit {@code BUY} signals and another {@code SELL} signals,
* and both will be accepted. If disallowed, once a {@link Strategy} enters a trade the signals emitted by another
* {@link Strategy} will be ignored.
*
* @return {@code false} if the {@link Strategy} that opens a trade must be the same {@link Strategy} that closes
* it, otherwise {@code true}
*/
public boolean allowMixedStrategies() {
return true;
}
/**
* Notifies that the latest price movement reached its highest positive point so far since the first {@link Order}
* in the given {@link Trade} was opened.
*
* @param trade a group of multiple orders that control the state of a position held by the {@link #trader}
* @param change the positive rate of return of the current trade (as a percentage value greater than 0.0 and in
* a scale of 100)
*/
public void highestProfit(Trade trade, double change) {
}
/**
* Notifies that the latest price movement reached its lowest negative point so far since the first {@link Order}
* * in the given {@link Trade} was opened.
*
* @param trade a group of multiple orders that control the state of a position held by the {@link #trader}
* @param change the negative rate of return of the current trade (as a percentage value between -100.0 and 0.0)
*/
public void worstLoss(Trade trade, double change) {
}
/**
* Notifies that the {@link #trader} opened an {@link Order} to buy some quantity of symbol {@link Trade#symbol()}
*
* @param trade a group of multiple orders that control the state of a position held by the {@link #trader}
* @param order the {@code BUY} order added to the given trade and available through (link {@link Trade#position()}).
*/
public void bought(Trade trade, Order order) {
}
/**
* Notifies that the {@link #trader} opened an {@link Order} to sell some quantity of symbol {@link Trade#symbol()}
*
* @param trade a group of multiple orders that control the state of a position held by the {@link #trader}
* @param order the {@code SELL} order added to the given trade and available through {@link Trade#exitOrders()}).
*/
public void sold(Trade trade, Order order) {
}
/**
* Confirms that a given trade can be closed.
*
* @param trade a group of multiple orders that control the state of a position held by the {@link #trader}
*
* @return {@code true} if the trade can be exited and a {@code SELL} order generated to sell all assets held by
* the account, otherwise {@code false}.
*/
public boolean allowExit(Trade trade) {
return true;
}
/**
* Checks if the current open position can be closed to release funds for another trade in another instrument to be opened.
*
* @param trade a group of multiple orders that control the state of a position held by the {@link #trader}
* @param exitSymbol the symbol of the instrument to be bought in case the current open trade can be closed (e.g. BTC, USD).
* @param candle the latest candle of the exit symbol ticker
* @param candleTicker the full ticker of the given candle (e.g. BTCETH, EURUSD)
*
* @return a flag indicating whether or not the current trade can be exited and the position reallocated to the given exit symbol.
*/
public boolean allowTradeSwitch(Trade trade, String exitSymbol, Candle candle, String candleTicker) {
return false;
}
/**
* Assigns the context associated with trading on a given symbol to this monitor.
*
* @param context the object responsible for all trading information of an instrument.
*/
public void setContext(Context context) {
if (this.context != null) {
throw new IllegalStateException("Can't modify context once it's set");
}
this.context = context;
this.trader = context.trader();
}
}