Automated Screenshots Based on Strategy Actions

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");


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:
1633098662675.png
 
Top