Flexible Budgets - Single Account

ツールアイコン

Google 広告 では、キャンペーンごとに 1 日の予算額を設定することができます。ただし、 マーケティング イニシアチブに関連する固定費用がかかる。たとえば 「秋のセールまでに 5,000 ドルかけたい」入札戦略により、 1 日の予算をどのように使うかはコントロールできるが、予算の使い方はコントロールできない キャンペーン期間中に予算が消費される。

たとえば、秋のセールの宣伝に 5, 000 ドルしか費やしたくないとします。 10 日間広告を掲載したい場合は、1 日の予算を 50, 000 円に設定します。 見積もることができます。ただし、このモデルでは費用が全額を その予算を均等に使いたい場合もあるでしょう。次の情報を Google 広告に指定できない 予算の大部分を過去数日間で使い切ろうとしている。

このスクリプトでは、独自の予算配分スキームを使用して、キャンペーンの予算を日単位で動的に調整することができます。

仕組み

予算設定方法のテスト

このスクリプトには、VM で実行した場合の影響をシミュレートするためのテストコードが含まれています。 数日。これにより、スクリプトを実行したときにどのような動作になるかを把握しやすくなります。 毎日一定期間にわたって実行されるように スケジュール設定されます

デフォルトでは、このスクリプトは、$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

スクリプトは、予算支出が 均等に分散されます。割り当てられた予算の上限に達すると、予算が設定される 費用がゼロになります

使用する関数を変更することで、使用する予算戦略を変更できます。 変更することもできます。このスクリプトには、事前に構築された次の 2 つの戦略が付属しています。 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)を取得し、それを日数の 2 倍で割ります。 残り。これにより、 あります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);
}

スケジュール

ローカル タイムゾーンの深夜 12 時かその直後に毎日スクリプトが実行されるようスケジュールを設定して、翌日にできるだけ多くの予算が配分されるようにします。注: ただし、取得したレポートデータ(費用など)は約 30% 遅延する costSoFar パラメータは前日の合計を参照している可能性があります。 午前 0 時以降に実行するようにスケジュール設定されているスクリプトです。

セットアップ

  • 下のボタンをクリックして、Google 広告アカウントでスクリプトを作成します。

    スクリプト テンプレートをインストールする

  • スクリプトを保存して、[プレビュー] ボタンをクリックします。このスクリプト( デフォルト)は、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}`);
}