danielputra
Active member
- Joined
- Jul 22, 2021
- Posts
- 29
- Likes
- 53
While a strategy is executing there is often not clear evidence afterwards how we got to the outcome we are seeing now. Logging output helps to some extend, having a screenshot of the chart(s) can provide valuable insights.
Therefore I created a way to make automated screenshots based on what is going on in a strategy class. As the SDK does not give us access to the Node class the chart is painted on, I had to go for a more generic solution. The screenshot made includes the data from all monitors connected to the computer.
I am posting my code here in case somebody else has the same requirement. Add this code to your strategy class (e.g. TradeManager).
Non-obvious imports due to Java classes having the same name in different packages:
import javafx.geometry.Rectangle2D;
import javafx.scene.robot.Robot;
The code requires a String field to be specified where the path to the screenshot folder is located:
private static final String SCREENSHOT_DIRECTORY = "screenshotDirectory";
group.addRow(new StringDescriptor(SCREENSHOT_DIRECTORY, "Screenshot Directory", null, 500, true, true));
The method below is called e.g. from method onOrderFilled:
createScreenshot(orderContext.getDataContext(), order, 500L, "FILLED1");
To build/compile the code in an IDE the 2 modules in the screenshot below are required:
Therefore I created a way to make automated screenshots based on what is going on in a strategy class. As the SDK does not give us access to the Node class the chart is painted on, I had to go for a more generic solution. The screenshot made includes the data from all monitors connected to the computer.
I am posting my code here in case somebody else has the same requirement. Add this code to your strategy class (e.g. TradeManager).
Non-obvious imports due to Java classes having the same name in different packages:
import javafx.geometry.Rectangle2D;
import javafx.scene.robot.Robot;
The code requires a String field to be specified where the path to the screenshot folder is located:
private static final String SCREENSHOT_DIRECTORY = "screenshotDirectory";
group.addRow(new StringDescriptor(SCREENSHOT_DIRECTORY, "Screenshot Directory", null, 500, true, true));
The method below is called e.g. from method onOrderFilled:
createScreenshot(orderContext.getDataContext(), order, 500L, "FILLED1");
Code:
/** Method creates one screenshot from all active monitors.
* @param dataContext MotiveWave dataContext.
* @param order The order which has been filled, modified or cancelled. Null if no order relates to this screenshot.
* @param delayInMillis Zero if no delay is required between execution of this method and taking the screenshot. Various operations like filling an order usually takes a few milliseconds, delaying the screenshot allows seeing the result.
* @param debugId String identifying where this method was called from within the strategy. This is useful for identifying the method in the strategy where the screenshot was initiated from. */
private void createScreenshot(final DataContext dataContext, final Order order, final long delayInMillis, final String debugId){
final String screenshotDirectoryFromSettings = getSettings().getString(SCREENSHOT_DIRECTORY);
if(screenshotDirectoryFromSettings != null && screenshotDirectoryFromSettings.trim().equals("") == false){
if(delayInMillis > 0L){
try{
Thread.sleep(delayInMillis);
}catch(InterruptedException exc){
exc.printStackTrace();
}
}
Platform.runLater(new Runnable(){
@Override public void run(){
try{
String screenshotDirectory = screenshotDirectoryFromSettings;
String dateAndTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd-'T'HH.mm.ss"));
Rectangle screenRectangle = new Rectangle(0, 0, 0, 0);
for(GraphicsDevice graphicsDevice : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()){
screenRectangle = screenRectangle.union(graphicsDevice.getDefaultConfiguration().getBounds());
}
if(screenshotDirectory.endsWith("/") == false && screenshotDirectory.endsWith("\\") == false){
screenshotDirectory += "/";
}
javafx.scene.robot.Robot robot = new Robot();
WritableImage writableImage = robot.getScreenCapture(null, new Rectangle2D(screenRectangle.getMinX(), screenRectangle.getMinY(), screenRectangle.getWidth(), screenRectangle.getHeight())); //Args: minX, minY, width, height
File file = new File(screenshotDirectory + dateAndTime + "-" + dataContext.getInstrument().getSymbol() + (order != null ? "-AC(" + order.getAccountId() + ")-OrderId(" + order.getOrderId() + ")" : "-TR" + TradeManager.this.instanceCounter) + (debugId != null ? "[" + debugId + "]" : "") + ".png");
ImageIO.write(SwingFXUtils.fromFXImage(writableImage, null), "png", file);
}catch(IOException exc){
exc.printStackTrace();
}
}
});
}
}
To build/compile the code in an IDE the 2 modules in the screenshot below are required: