灵活预算 - 单一账号

工具图标

在 Google Ads 中,您可以为每个广告系列设置每日预算金额。不过, 相关营销活动的费用是固定的;例如 “我想花 5000 美元来宣传我们的秋季促销活动”。出价策略 您可以有效控制每日预算的支出方式, 广告系列在广告系列投放期间所消耗的预算

例如,假设我们只想花 5000 元来宣传秋季促销活动 如果希望投放 10 天的广告活动 我们可以将每日预算设置为 500 元 全部预算。不过,这种方法假设我们将支出全部金额 并且希望平均支出预算您无法告知 Google Ads 您希望在最后几天支出大部分预算。

此脚本却可以按照自定义的预算分配方案每天动态调整广告系列预算。

工作原理

测试预算策略

该脚本包含一些测试代码,用于模拟运行 。这样,您就可以更清楚地了解 在一个时间段内安排每天运行一次。

默认情况下,此脚本会模拟平均分配预算(支出 $500) 10 天以上。

function main() {
  testBudgetStrategy(calculateBudgetEvenly, 10, 500);
  // setNewBudget(calculateBudgetEvenly, CAMPAIGN_NAME, TOTAL_BUDGET, START_DATE, END_DATE);
}

setNewBudget 函数调用已被注释掉,表明它只会运行 测试代码。以下是上述示例的输出结果:

Day 1.0 of 10.0, new budget 50.0, cost so far 0.0
Day 2.0 of 10.0, new budget 50.0, cost so far 50.0
Day 3.0 of 10.0, new budget 50.0, cost so far 100.0
Day 4.0 of 10.0, new budget 50.0, cost so far 150.0
Day 5.0 of 10.0, new budget 50.0, cost so far 200.0
Day 6.0 of 10.0, new budget 50.0, cost so far 250.0
Day 7.0 of 10.0, new budget 50.0, cost so far 300.0
Day 8.0 of 10.0, new budget 50.0, cost so far 350.0
Day 9.0 of 10.0, new budget 50.0, cost so far 400.0
Day 10.0 of 10.0, new budget 50.0, cost so far 450.0
Day 11.0 of 10.0, new budget 0.0, cost so far 500.0

脚本每天都会计算新预算,以确保预算支出 均匀分配。达到分配的预算上限后,系统就会设置预算 零支出。

您可以通过更改所使用的函数来更改所使用的预算策略,或者 修改函数本身。该脚本有两个预构建的策略: calculateBudgetEvenlycalculateBudgetWeighted。设置加权测试 预算策略,请按如下方式更改 testBudgetStrategy

testBudgetStrategy(calculateBudgetWeighted, 10, 500);

点击预览并检查记录器输出。请注意,此预算策略 在前几天分配较少的预算,而在最后几天分配较多的预算。

您可以使用这种测试方法来模拟预算计算函数的变更,并尝试用自己的方法分配预算。

分配预算

calculateBudgetWeighted预算策略通过以下途径实施: 函数:

function calculateBudgetWeighted(costSoFar, totalBudget, daysSoFar, totalDays) {
  const daysRemaining = totalDays - daysSoFar;
  const budgetRemaining = totalBudget - costSoFar;
  if (daysRemaining <= 0) {
    return budgetRemaining;
  } else {
    return budgetRemaining / (2 * daysRemaining - 1) ;
  }
}

此函数采用以下参数:

costSoFar
广告系列从 START_DATE至今的累积费用。
totalBudget
将支出从 START_DATE分配给 END_DATE
daysSoFar
START_DATE到今天的天数。
totalDays
START_DATEEND_DATE 之间的总天数。

您可以编写自己的函数,但必须包含这些参数。使用这些值,您可以比较到目前为止已经支出的金额与总预算金额,并确定您当前在整个预算时间表内的位置。

具体来说,此预算策略会计算还有多少预算 (totalBudget - costSoFar),然后除以天数的两倍 剩余时间。该指标会衡量广告系列在广告系列投放期末 广告系列。使用自 START_DATE 以来的费用,它还将“慢会话”也考虑在内 天”也就是所设预算不会全部用完的情况

根据真实情况设置预算

对预算策略感到满意后,您需要进行一些更改 然后再安排此脚本每天运行。

首先,更新文件顶部的常量:

  • START_DATE:将此列设置为预算策略的起始值。此值应为 当前日期或过去的某一天。
  • END_DATE:将此设为使用此预算投放广告的最后一天。
  • TOTAL_BUDGET:您要支出的总金额。该值属于 可能会超出该值,具体取决于脚本是 投放时间
  • CAMPAIGN_NAME:要应用此预算策略的广告系列的名称。

接下来,停用测试并启用逻辑来实际更改预算:

function main() {
  // testBudgetStrategy(calculateBudgetEvenly, 10, 500);
  setNewBudget(calculateBudgetWeighted, CAMPAIGN_NAME, TOTAL_BUDGET, START_DATE, END_DATE);
}

时间安排

将此脚本设置为每天在本地时区的午夜或过后不久运行,从而尽可能地充分利用新的一天的预算。请注意: 但是,检索到的报告数据(如费用)可能会延迟大约 3 因此 costSoFar 参数可能会引用前一天的某 安排在午夜后运行。

设置

  • 点击下面的按钮,在您的 Google Ads 账号中创建脚本。

    安装脚本模板

  • 保存脚本并点击预览按钮。此脚本(通过 默认)模拟 10 天 500 元的预算策略。记录器输出 反映的是所模拟的日期、为该日期分配的预算,以及 迄今为止的支出总额。

源代码

// Copyright 2015, Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @name Flexible Budgets
 *
 * @overview The Flexible budgets script dynamically adjusts campaign budget for
 *     an advertiser account with a custom budget distribution scheme on a daily
 *     basis. See
 *     https://developers.google.com/google-ads/scripts/docs/solutions/flexible-budgets
 *     for more details.
 *
 * @author Google Ads Scripts Team [adwords-scripts@googlegroups.com]
 *
 * @version 2.1
 *
 * @changelog
 * - version 2.1
 *   - Split into info, config, and code.
 * - version 2.0
 *   - Updated to use new Google Ads scripts features.
 * - version 1.0.3
 *   - Add support for video and shopping campaigns.
 * - version 1.0.2
 *   - Use setAmount on the budget instead of campaign.setBudget.
 * - version 1.0.1
 *   - Improvements to time zone handling.
 * - version 1.0
 *   - Released initial version.
 */

/**
 * Configuration to be used for the Flexible Budgets script.
 */

CONFIG = {
  'total_budget': 500,
  'campaign_name': 'Special Promotion',
  'start_date': 'November 1, 2021 0:00:00 -0500',
  'end_date': 'December 1, 2021 0:00:00 -0500'
};

const TOTAL_BUDGET = CONFIG.total_budget;
const CAMPAIGN_NAME = CONFIG.campaign_name;
const START_DATE = new Date(CONFIG.start_date);
const END_DATE = new Date(CONFIG.end_date);

function main() {
  testBudgetStrategy(calculateBudgetEvenly, 10, 500);
//  setNewBudget(calculateBudgetEvenly, CAMPAIGN_NAME, TOTAL_BUDGET,
//      START_DATE, END_DATE);
}

function setNewBudget(budgetFunction, campaignName, totalBudget, start, end) {
  const today = new Date();
  if (today < start) {
    console.log('Not ready to set budget yet');
    return;
  }
  const campaign = getCampaign(campaignName);
  const costSoFar = campaign.getStatsFor(
        getDateStringInTimeZone('yyyyMMdd', start),
        getDateStringInTimeZone('yyyyMMdd', end)).getCost();
  const daysSoFar = datediff(start, today);
  const totalDays = datediff(start, end);
  const newBudget = budgetFunction(costSoFar, totalBudget, daysSoFar,
                                   totalDays);
  campaign.getBudget().setAmount(newBudget);
}

function calculateBudgetEvenly(costSoFar, totalBudget, daysSoFar, totalDays) {
  const daysRemaining = totalDays - daysSoFar;
  const budgetRemaining = totalBudget - costSoFar;
  if (daysRemaining <= 0) {
    return budgetRemaining;
  } else {
    return budgetRemaining / daysRemaining;
  }
}

function calculateBudgetWeighted(costSoFar, totalBudget, daysSoFar,
    totalDays) {
  const daysRemaining = totalDays - daysSoFar;
  const budgetRemaining = totalBudget - costSoFar;
  if (daysRemaining <= 0) {
    return budgetRemaining;
  } else {
    return budgetRemaining / (2 * daysRemaining - 1);
  }
}

function testBudgetStrategy(budgetFunc, totalDays, totalBudget) {
  let daysSoFar = 0;
  let costSoFar = 0;
  while (daysSoFar <= totalDays + 2) {
    const newBudget = budgetFunc(costSoFar, totalBudget, daysSoFar, totalDays);
    console.log(`Day ${daysSoFar + 1} of ${totalDays}, new budget ` +
                `${newBudget}, cost so far ${costSoFar}`);
    costSoFar += newBudget;
    daysSoFar += 1;
  }
}

/**
 * Returns number of days between two dates, rounded up to nearest whole day.
 */
function datediff(from, to) {
  const millisPerDay = 1000 * 60 * 60 * 24;
  return Math.ceil((to - from) / millisPerDay);
}

function getDateStringInTimeZone(format, date, timeZone) {
  date = date || new Date();
  timeZone = timeZone || AdsApp.currentAccount().getTimeZone();
  return Utilities.formatDate(date, timeZone, format);
}

/**
 * Finds a campaign by name, whether it is a regular, video, or shopping
 * campaign, by trying all in sequence until it finds one.
 *
 * @param {string} campaignName The campaign name to find.
 * @return {Object} The campaign found, or null if none was found.
 */
function getCampaign(campaignName) {
  const selectors = [AdsApp.campaigns(), AdsApp.videoCampaigns(),
      AdsApp.shoppingCampaigns()];
  for (const selector of selectors) {
    const campaignIter = selector
        .withCondition(`CampaignName = "${campaignName}"`)
        .get();
    if (campaignIter.hasNext()) {
      return campaignIter.next();
    }
  }
  throw new Error(`Could not find specified campaign: ${campaignName}`);
}