Draw with the Mouse on the Canvas using JavaScript

Below is a simple example of drawing with the mouse on an HTML5 Canvas element in the browser using JavaScript.

The example uses Vanilla JavaScript and HTML5.

Overall, the code sets up event handler functions for the mouse button being held down, released, and while the mouse is being moved.

The flag isDrawing controls whether a line is drawn to the target point (targetX, targetY).

The flag is turned on when the mouse is held down, and turned off when the mouse is released.

Note that the coordinates of points start at the top left of the canvas, and grow down and to the right.

The coordinates of the current mouse pointer position are passed into the event handlers as e.pageX and e.pageY.

The page coordinates are relative to the entire page, so there is an offset to the canvas element’s top left. Therefore, to get the correct final drawing coordinates, we use:

targetX = e.pageX - canvas.offsetLeft;
targetY = e.pageY - canvas.offsetTop;

The canvas functions beginPath() and closePath() start and stop the drawing path.
The path is opened on mouse down, and closed on mouse up.
The actual drawing is executed with the canvas method stroke().

The HTML file and JavaScript file are below.

draw-on-canvas.html
<html>

  <head>
    <title>Draw on the Canvas</title>
    <script src="draw-on-canvas.js" type="module">
    </script>
  </head>

  <body>
    <canvas id="myCanvas" width="500" height="500">
    </canvas>
  </body>

</html>
draw-on-canvas.js
// State variables.
let canvas = null;
let context = null; // Drawing context.
let isDrawing = false;

// Set canvas context, attach event handlers.
window.onload = function() {
  canvas = document.getElementById("myCanvas");
  context = canvas.getContext("2d");

  isDrawing = false;

  canvas.addEventListener("mousedown", startDrawing);
  canvas.addEventListener("mouseup", stopDrawing);
  canvas.addEventListener("mousemove", draw);
}

// Mouse down: enter drawing state.
const startDrawing = function(e) {
  isDrawing = true;

  // Coordinates within canvas.
  let targetX = e.pageX - canvas.offsetLeft;
  let targetY = e.pageY - canvas.offsetTop;

  // Start a new drawing path and move pen there.
  context.beginPath();
  context.moveTo(targetX, targetY);
}

// Mouse up: exit drawing state.
const stopDrawing = function(e) {
  isDrawing = false;
  context.closePath();
}

// Mouse move: continuous drawing when flag on.
const draw = function(e) {
  if (isDrawing) {
    let targetX = e.pageX - canvas.offsetLeft;
    let targetY = e.pageY - canvas.offsetTop;
    context.lineTo(targetX, targetY);
    context.stroke(); // Draw line.
  }
}

 

Get a Stock Quote Using the Unofficial Webull API

We can get a quote for the latest price of a stock ticker which is close to real-time data using the unofficial Webull API.
The delay compared to real-time streaming data should be 1 to 2 seconds at most, but this should not be used for applications where the recency of data is critically important.

Make sure the module is installed:

$ pip install webull

The script is below. Note that there are two possible fields in the response JSON data for the last price: “close” and “pPrice”. At the time of writing “close” is present, but “pPrice” is present in older data examples. Because the API is not officially supported or documented, this field may change again. If neither of the known fields are present, the script reports an error.
The name of the ticker to search for is taken from the standard input.

from webull import webull

wb = webull()

ticker = input("Ticker symbol: ")

try:
  stockData = wb.get_quote(ticker)
except ValueError as e:
  print("Exception reading from Webull API: ")
  print(e)

if "pPrice" in stockData:
  # Current price field in some data.
  lastPrice = stockData["pPrice"]
  print("Price: " + str(lastPrice))
elif "close" in stockData:
  # Current Close of the current candle, i.e. last price.
  lastPrice = stockData["close"]
  print("Price: " + str(lastPrice))
else:
  # May happen if the data format is changed.
  print("Price field missing.")

Example input and output:

Ticker symbol: TSLA
Price: 490.73

References

https://pypi.org/project/webull

https://github.com/tedchou12/webull

 

Run a Multimodal Model Locally with Ollama

This example shows how to run a Multi-Modal Large Language Model (LLM) locally to describe an image through Ollama in Python.

The model used is Qwen 2.5 VL (Vision Language).

Install it with Ollama:

$ ollama run qwen2.5vl:latest

The image file is a regular JPEG file stored locally.
We assume the file is stored in the same directory as the script and is named “duck.jpeg”.

Ensure the Python Ollama library is installed using:

$ pip install ollama

We call the model with the chat() function.

The response object contains the resulting description in an object called “message”, and specifically the field “content”.

Complete script:

from ollama import chat

response = chat(
  model='qwen2.5vl',
  messages=[
    {
      'role': 'user',
      'content': 'Describe this image',
      'images': ['./duck.jpeg']
    }
  ]
)

resultDescription = response['message']['content']

print(resultDescription)

Example output:

The image shows a yellow rubber duck floating in a pool of water. 
The rubber duck is wearing black sunglasses and has a red beak. 
The water around the duck is clear and blue, 
with gentle ripples reflecting the duck and its sunglasses. 
The overall scene conveys a playful and summery atmosphere, 
often associated with leisure and fun in a pool setting.

 

Get News for a Ticker with the IBKR API

This example shows how to get News items for a stock given its ticker symbol using the Interactive Brokers (IBKR) API in Python.

The API distinguishes Historical News from streaming, real-time news.
This post is about historical news, i.e. a list of dates sorted by time.
This is different from subscribing to News ticks and listening for new news events.

Note that we need to get the Contract ID for the ticker symbol first.
The Contract ID (conId) is stored inside the IBapi object for later use.

This is done in contractDetails().

The default, freely available news sources in the API are:

  • Briefing.com General Market Columns (BRFG)
  • Briefing.com Analyst Actions (BRFUPDN)
  • Dow Jones Newsletters (DJNL)

If you are subscribed to more news sources, they can be included in the API results given the proper codes.

Some other things to note:

  • The API returns headlines with extra metadata such as language inside braces ({…}). We filter these out using a regular expression as there does not seem to be any way to omit them from the results.
  • IBKR Trader Workstation (TWS) is assumed to be running on localhost.

Complete script:

import re
import threading
import time

from datetime import datetime, timedelta

from ibapi.client import EClient, Contract
from ibapi.contract import ContractDetails
from ibapi.wrapper import EWrapper

# Extend IBKR scanner base class.
class IBapi(EClient, EWrapper):
  def __init__(self):
    EClient.__init__(self, self)

  def contractDetails(self, reqId: int, contractDetails: ContractDetails):
    print(f"Ticker: {contractDetails.contract.symbol}, conId: {contractDetails.contract.conId}")
    self.conId = contractDetails.contract.conId

  def historicalNews(self, requestId, timeStamp, providerCode, articleId, headline):
    print(timeStamp + " " + self.cleanHeadline(headline))

  # Remove metadata often included in the headline within "{...}", sometimes with "!".
  def cleanHeadline(self, headline):
    return re.sub("\{.*?}!?", "", headline)

# Main script.
TWS_HOST = "127.0.0.1"
TWS_PORT = 7497
CLIENT_ID = 12345

ticker = input("Ticker symbol: ")

ibApi = IBapi()
ibApi.connect(TWS_HOST, TWS_PORT, CLIENT_ID)
threading.Thread(target=ibApi.run).start()
time.sleep(5) # Allow time for subscription.

# Contract object for the stock.
contract = Contract()
contract.symbol = ticker
contract.secType = "STK" # Stocks.
contract.exchange = "SMART"
contract.currency = "USD"

ibApi.reqContractDetails(
  reqId=101,
  contract=contract
)

time.sleep(3) # Allow time to get contract details.

PROVIDERS = "BRFG+BRFUPDN+DJNL" # Briefing.com, Dow Jones Newsletters.
TOTAL_RESULTS = 15
LOOKBACK_DAYS = 10 # Num days from now to oldest news.
DATE_FORMAT = "%Y%m%d %H:%M:%S"

currentDatetime = datetime.now()
currentDatetimeFormatted = currentDatetime.strftime(DATE_FORMAT)

tenDaysAgo = currentDatetime - timedelta(days=LOOKBACK_DAYS)
tenDaysAgoFormatted = tenDaysAgo.strftime(DATE_FORMAT)

ibApi.reqHistoricalNews(
  reqId=102,
  conId=ibApi.conId, # Contract ID for ticker.
  providerCodes=PROVIDERS,
  startDateTime=tenDaysAgoFormatted,
  endDateTime=currentDatetimeFormatted,
  totalResults=TOTAL_RESULTS,
  historicalNewsOptions=[]
)

time.sleep(1)
ibApi.disconnect()

Example run:

Ticker symbol: TSLA
Ticker: TSLA, conId: 76792991
2025-10-02 14:19:54.0 Tesla cruises past Q3 delivery estimates, but tax credit pull-forward clouds Q4 outlook
2025-09-30 14:59:17.0 Canaccord Genuity reiterated Tesla (TSLA) coverage with Buy and target $490
2025-09-26 11:49:39.0 Deutsche Bank reiterated Tesla (TSLA) coverage with Buy and target $435
2025-09-23 11:51:14.0 Mizuho reiterated Tesla (TSLA) coverage with Outperform and target $450
2025-09-22 12:57:41.0 Piper Sandler reiterated Tesla (TSLA) coverage with Overweight and target $500
2025-09-19 12:20:40.0 Robert W. Baird upgraded Tesla (TSLA) to Outperform with target $548
2025-09-18 17:11:04.0 Goldman reiterated Tesla (TSLA) coverage with Neutral and target $395
2025-09-15 14:03:38.0 Tesla's Musk makes bold $1 bln stock bet amid EV headwinds and AI ambitions
2025-07-29 12:14:24.0 RBC Capital Mkts reiterated Tesla (TSLA) coverage with Outperform and target $325
2025-07-25 13:00:32.0 China Renaissance downgraded Tesla (TSLA) to Hold with target $349
2025-07-24 14:20:22.0 Tesla's better-than-feared Q2 results overshadowed by Musk's cautious outlook
2025-07-24 11:54:12.0 Canaccord Genuity reiterated Tesla (TSLA) coverage with Buy and target $333
2025-07-07 12:14:59.0 William Blair downgraded Tesla (TSLA) to Mkt Perform
2025-07-01 14:10:42.0 Tesla shares slide as Trump targets Musk's EV subsidies in public spat
2025-06-26 12:32:13.0 The Benchmark Company reiterated Tesla (TSLA) coverage with Buy and target $475

Note:

It is also possible to get entire articles with reqNewsArticle().

References

https://interactivebrokers.github.io/tws-api/news.html

 

Iterate over a Range of Characters in Perl

To easily iterate over a range of characters in Perl, we can use the range operator to define an array of chars.
Then, we can iterate over each element with a for-each loop.
This can be useful when iterating over objects named alphabetically instead of numerically, for example.

The code is below.

use strict;

my @chars = ('a'..'z');

foreach my $c (@chars) {
  print("Current char: $c \n");
}

Truncated output:

Current char: a
Current char: b
Current char: c
Current char: d
Current char: e
Current char: f
...

Current char: z

 

Get Short Share Borrow Availability using the IBKR API

The following script shows how to retrieve a value indicating if a stock has shares available to borrow to sell short in the Interactive Brokers (IBKR) system.

First, make sure the IBKR API for Python is installed:

$ pip install ibapi

We assume Trader Workstation (TWS) is running locally and allows connections from EClients.

The script takes the ticker symbol as input.

The class extending EClient and EWrapper allows us to implement an event handler: tickGeneric(). We will subscribe to the tick indicating short share availability and the data will be received via this callback.

Note the value for genericTickList is “236” in the call to reqMktData() to subscribe to the short shares available tick.

Note that there will be a delay before the generic tick event fires and future updates are not frequent.

Use CTRL-C to exit.

Complete script:

import threading
import time

from ibapi.client import EClient, Contract
from ibapi.wrapper import EWrapper

# Extend IBKR scanner base class.
class IBapi(EClient, EWrapper):
  def __init__(self):
    EClient.__init__(self, self)

  def tickGeneric(self, reqId, tickType, value):
    if tickType == 46:
      print("Value (short shares available indicator): " + str(value))
      # Indicator value interpreted according to the docs:
      # https://interactivebrokers.github.io/tws-api/tick_types.html
      if value <= 1.5:
        print("Not available for short sale.")
      if value > 1.5 and value <= 2.5:
        print("Hard to borrow. Locate required.")
      if value > 2.5:
        print("Easy to borrow. At least 1000 shares available.")

# Main script.
TWS_HOST = "127.0.0.1"
TWS_PORT = 7497
CLIENT_ID = 12345

ticker = input("Ticker symbol: ")

app = IBapi()
app.connect(TWS_HOST, TWS_PORT, CLIENT_ID)
threading.Thread(target=app.run).start()
time.sleep(5) # Allow time for subscription.

contract = Contract()
contract.symbol = ticker
contract.secType = "STK" # Stocks.
contract.exchange = "SMART"
contract.currency = "USD"

app.reqMarketDataType(3) # Delayed streaming data.
app.reqMktData(reqId=100, # Arbitrary ID.
  contract=contract,
  genericTickList="236", # Includes borrow availability.
  snapshot=False,
  regulatorySnapshot=False,
  mktDataOptions=[]
)

Example input and output:

Ticker symbol: TRIB
Value (short shares available indicator): 3.0
Easy to borrow. At least 1000 shares available.

References

https://interactivebrokers.github.io/tws-api/tick_types.html

 

Validate XML Syntax in the Command Line

This example shows how to parse and validate XML in the terminal using the command xmllint.
Note that this is testing if the document is well formed, i.e. has correct syntax, not validity according to a specific schema.

Input file: items.xml

<items>
  <item>
    <name>A</name>
  </item>
  <item>
    <name>B</name>
  </item>
</items>

Test the file:

$ xmllint items.xml

For a valid file, the output will be a copy of the entire file, without error messages:

<?xml version="1.0"?>
<items>
  <item>
    <name>A</name>
  </item>
  <item>
    <name>B</name>
  </item>
</items>

If there is a syntax error, as below, the line number will be reported.

Input file with error: items.xml

<items>
  <item>
    <name>A<name> <!-- improper close tag -->
  </item>
  <item>
    <name>B</name>
  </item>
</items>

The error output will look like this:

items.xml:4: parser error : 
Opening and ending tag mismatch: name line 3 and item
</item>
^
items.xml:8: parser error : 
Opening and ending tag mismatch: name line 3 and items
</items>
^
items.xml:11: parser error : 
Premature end of data in tag item line 2

^

 

Get the Top Percentage Gainers using the IBKR API in Python

This example shows how to get a list of the top gainers on the day in US stocks using the Interactive Brokers (IBKR) API for Python.

The API works by connecting to a locally running Trader Workstation (TWS) instance. Make sure TWS is up and running; both live trading a paper trading logins will work.

In TWS, we need to enable EClients in TWS under Global Configuration / API. This will allow clients from localhost to connect to TWS over HTTP.

Install the IBKR API package using:

$ pip install ibapi

We extend both EClient and EWrapper to inherit the functionality of reading the scanner feed.
We call the scannerData() method of the superclass to get the actual data. We can ignore most of the parameters to scannerData(), but need to include them to match the signature.

Note that we need to launch a listener in a thread in parallel to the main script.
We connect to the data feed, read some items and disconnect.

The following script will get the first ten of the top percentage gainers at the time it is run:

import time
import threading

from ibapi.client import EClient
from ibapi.scanner import ScannerSubscription
from ibapi.wrapper import EWrapper

# Class extending IBKR scanner base classes.
class IBapi(EWrapper, EClient):
  def __init__(self):
    EClient.__init__(self, self)

  def scannerData(self, reqId, rank, contractDetails, distance, benchmark, projection, legsStr):
    super().scannerData(reqId, rank, contractDetails, distance, benchmark, projection, legsStr)
    position = rank + 1 # Zero based indexing.
    print(f"{position}: {contractDetails.contract.symbol}")

  def scannerDataEnd(self, reqId):
    print("End of scanner data.")
    self.disconnect()

# Function to run continuously.
def ibApiRunLoop(ibApiApp):
  ibApiApp.run()

# Main script.

TWS_HOST = '127.0.0.1'
TWS_PORT = 7497
CLIENT_ID = 12345

ibApi = IBapi()
ibApi.connect(TWS_HOST, TWS_PORT, CLIENT_ID)

thread = threading.Thread(target=ibApiRunLoop, args=(ibApi,), daemon=True)
thread.start()

time.sleep(1) # Allow time for connection.

scannerSub = ScannerSubscription()
scannerSub.numberOfRows = 10
scannerSub.instrument='STK' # Stocks.
scannerSub.locationCode='STK.US.MAJOR' # US major exchanges.
scannerSub.scanCode='TOP_PERC_GAIN' # Top percentage gainers.

requestId = 1000 # An arbitrary request ID.
filters = [] # No special filters needed.

ibApi.reqScannerSubscription(requestId, scannerSub, filters, filters)

time.sleep(5) # Allow time to receive data.

ibApi.disconnect()

Example output:

1: LUCY
2: TNMG
3: DEVS
4: SRXH
5: SMCX
6: SMCL
7: LOBO
8: LGMK
9: HIMZ
10: SMCI
End of scanner data.

Note that to get more details, e.g. the last price of the tickers, we need to query data specific to each ticker.

References

https://www.interactivebrokers.com/campus/ibkr-quant-news/interactive-brokers-python-api-native-a-step-by-step-guide/

https://www.interactivebrokers.com/campus/ibkr-quant-news/implementing-market-scanners-using-tws-api-part-ii/

 

Get the Float Size of a Stock with Yahoo Finance Data

The following example shows how to retrieve the value of the float of a stock in Python using the Yahoo Finance (yfinance) library.

Note that there is no value returned specifically for Free Float, but Float Size should be equal or close enough for many purposes.

The following script retrieves the float size for any ticker symbol provided as input.

The float is under the Key Statistics (keyStats).

import yfinance as yf

ticker = input("Ticker symbol: ")

stock = yf.Ticker(ticker)

keyStats = stock.info

floatShares = keyStats.get("floatShares")

print("Float size: " + str(floatShares))

Example run:

Ticker symbol: AREB
Float size: 1026592

 

Scraping a Web Page with Python and BeautifulSoup

The following is a simple example showing how to scrape a web page in Python using the BeautifulSoup library.

The example web page we use is Hacker News:

https://news.ycombinator.com/

The goal of the example is to print just the headlines from the page.

Scraping and parsing a web page requires first understanding the HTML document structure of the target page.
In this case, the relevant portion of the HTML structure is roughly as follows:

<table>
 <tbody>
  <tr>
   ...
   <td>
    <span class="titleline">
     <a href="https://...">Headline</a>
    </span>
   </td>
   ...

Crucially, BeautifulSoup can find elements by many different criteria, regardless of depth of nesting.

One of the most useful techniques is searching by CSS class. In this case, we need to find anchor elements inside spans with the class “titleline”, inside table cells.

First, we create a BeautifulSoup object and use the find methods to drill down into the HTML elements in the DOM.

Note that findAll() finds a list of elements, while find() gets a single element.

The entire script is below.

scrape-example.py
from bs4 import BeautifulSoup
from urllib import request

url = "https://news.ycombinator.com/"

htmlPage = request.urlopen(url)

soup = BeautifulSoup(htmlPage, "html.parser")

# Find list of elements by CSS class.
spanList = soup.findAll(
  "span", 
  attrs={"class": "titleline"}
)

for span in spanList:
  anchor = span.find("a")
  headline = anchor.text
  print(headline)

Running the script:

$ python scrape-example.py

Example output of headlines:

The subtle art of designing physical controls for cars
WASM will replace containers
Backblaze Drive Stats for 2024

...