Example 2: Price Action with Moving Average
This strategy uses historical price data to calculate a simple moving average and makes decisions based on price crossing the average.
class Strategy {
constructor() {
this.strategy = {
data: {
token: {
address: "",
creationTime: 0
},
priceTicks: []
},
steps: [
{
run: (entry, current) => this.buyOnMACross(entry, current),
label: "Buy when price crosses above 20-period MA"
},
{
run: (entry, current) => this.sellOnMACross(entry, current),
label: "Sell when price crosses below 20-period MA"
}
],
context: {}
}
}
/**
* Calculate simple moving average from priceTicks
* @param {number} periods - Number of periods to average
* @returns {number|null} - Average price or null if not enough data
*/
calculateMA(periods) {
const ticks = this.strategy.data.priceTicks;
// Need at least 'periods' ticks to calculate MA
if (ticks.length < periods) {
return null;
}
// Sum up the last 'periods' prices
let sum = 0;
for (let i = 0; i < periods; i++) {
sum += ticks[i].usdPrice;
}
return sum / periods;
}
/**
* Step 1: Buy when price crosses above moving average
* Confirms that previous price was below MA (actual cross)
*/
buyOnMACross(signalPrice, currentPrice) {
const ma = this.calculateMA(20);
// Not enough data yet
if (ma === null) {
return null;
}
// Get previous price (if available)
const ticks = this.strategy.data.priceTicks;
const previousPrice = ticks.length >= 2 ? ticks[1].usdPrice : null;
// Check for bullish cross:
// - Current price is above MA
// - Previous price was below MA (confirms cross)
// - Price is within 20% of signal (not chasing too much)
const isPriceAboveMA = currentPrice > ma;
const wasPriceBelowMA = previousPrice ? previousPrice < ma : false;
const isWithinRange = currentPrice <= signalPrice * 1.2;
if (isPriceAboveMA && wasPriceBelowMA && isWithinRange) {
// Store MA value for reference
this.strategy.context.entryMA = ma;
this.strategy.context.entryTime = Date.now();
return {
buy: true,
partToBuyInPercentage: 100
};
}
return null;
}
/**
* Step 2: Sell when price crosses below moving average
* Waits for at least 2x profit OR bearish MA cross
*/
sellOnMACross(entryPrice, currentPrice) {
const ma = this.calculateMA(20);
// Not enough data yet
if (ma === null) {
return null;
}
const multiplier = currentPrice / entryPrice;
// Take profit at 3x regardless of MA
if (multiplier >= 3.0) {
return {
sell: true,
partToSellInPercentage: 100
};
}
// Get previous price
const ticks = this.strategy.data.priceTicks;
const previousPrice = ticks.length >= 2 ? ticks[1].usdPrice : null;
// Check for bearish cross:
// - Current price is below MA
// - Previous price was above MA
// - At least 1.5x profit (don't exit too early)
const isPriceBelowMA = currentPrice < ma;
const wasPriceAboveMA = previousPrice ? previousPrice > ma : false;
const hasMinProfit = multiplier >= 1.5;
if (isPriceBelowMA && wasPriceAboveMA && hasMinProfit) {
return {
sell: true,
partToSellInPercentage: 100
};
}
return null;
}
}Key Concepts Demonstrated
Using priceTicks array: Accessing historical price data to calculate indicators
Custom Calculations: Implementing your own technical analysis (moving average)
Lookback Logic: Checking previous price to confirm crosses (not just levels)
Risk Management: Requiring minimum profit before allowing MA-based exits
Hard Take Profit: Having an absolute exit level regardless of indicator
PreviousExample 1: Multi-Phase DCA Exit with Trailing StopNextExample 3: Volatility-Based Position Sizing
Last updated
